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);
7915 field.setValue(values[id]);
7919 if(this.trackResetOnLoad){
7920 field.originalValue = field.getValue();
7926 //Roo.each(this.childForms || [], function (f) {
7927 // f.setValues(values);
7934 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7935 * they are returned as an array.
7936 * @param {Boolean} asString
7939 getValues : function(asString){
7940 //if (this.childForms) {
7941 // copy values from the child forms
7942 // Roo.each(this.childForms, function (f) {
7943 // this.setValues(f.getValues());
7949 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7950 if(asString === true){
7953 return Roo.urlDecode(fs);
7957 * Returns the fields in this form as an object with key/value pairs.
7958 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7961 getFieldValues : function(with_hidden)
7963 var items = this.getItems();
7965 items.each(function(f){
7969 var v = f.getValue();
7970 if (f.inputType =='radio') {
7971 if (typeof(ret[f.getName()]) == 'undefined') {
7972 ret[f.getName()] = ''; // empty..
7975 if (!f.el.dom.checked) {
7983 // not sure if this supported any more..
7984 if ((typeof(v) == 'object') && f.getRawValue) {
7985 v = f.getRawValue() ; // dates..
7987 // combo boxes where name != hiddenName...
7988 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7989 ret[f.name] = f.getRawValue();
7991 ret[f.getName()] = v;
7998 * Clears all invalid messages in this form.
7999 * @return {BasicForm} this
8001 clearInvalid : function(){
8002 var items = this.getItems();
8004 items.each(function(f){
8015 * @return {BasicForm} this
8018 var items = this.getItems();
8019 items.each(function(f){
8023 Roo.each(this.childForms || [], function (f) {
8030 getItems : function()
8032 var r=new Roo.util.MixedCollection(false, function(o){
8033 return o.id || (o.id = Roo.id());
8035 var iter = function(el) {
8042 Roo.each(el.items,function(e) {
8059 Roo.apply(Roo.bootstrap.Form, {
8086 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8087 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8088 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8089 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8092 this.maskEl.top.enableDisplayMode("block");
8093 this.maskEl.left.enableDisplayMode("block");
8094 this.maskEl.bottom.enableDisplayMode("block");
8095 this.maskEl.right.enableDisplayMode("block");
8097 this.toolTip = new Roo.bootstrap.Tooltip({
8098 cls : 'roo-form-error-popover',
8100 'left' : ['r-l', [-2,0], 'right'],
8101 'right' : ['l-r', [2,0], 'left'],
8102 'bottom' : ['tl-bl', [0,2], 'top'],
8103 'top' : [ 'bl-tl', [0,-2], 'bottom']
8107 this.toolTip.render(Roo.get(document.body));
8109 this.toolTip.el.enableDisplayMode("block");
8111 Roo.get(document.body).on('click', function(){
8115 Roo.get(document.body).on('touchstart', function(){
8119 this.isApplied = true
8122 mask : function(form, target)
8126 this.target = target;
8128 if(!this.form.errorMask || !target.el){
8132 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8134 Roo.log(scrollable);
8136 var ot = this.target.el.calcOffsetsTo(scrollable);
8138 var scrollTo = ot[1] - this.form.maskOffset;
8140 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8142 scrollable.scrollTo('top', scrollTo);
8144 var box = this.target.el.getBox();
8146 var zIndex = Roo.bootstrap.Modal.zIndex++;
8149 this.maskEl.top.setStyle('position', 'absolute');
8150 this.maskEl.top.setStyle('z-index', zIndex);
8151 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8152 this.maskEl.top.setLeft(0);
8153 this.maskEl.top.setTop(0);
8154 this.maskEl.top.show();
8156 this.maskEl.left.setStyle('position', 'absolute');
8157 this.maskEl.left.setStyle('z-index', zIndex);
8158 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8159 this.maskEl.left.setLeft(0);
8160 this.maskEl.left.setTop(box.y - this.padding);
8161 this.maskEl.left.show();
8163 this.maskEl.bottom.setStyle('position', 'absolute');
8164 this.maskEl.bottom.setStyle('z-index', zIndex);
8165 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8166 this.maskEl.bottom.setLeft(0);
8167 this.maskEl.bottom.setTop(box.bottom + this.padding);
8168 this.maskEl.bottom.show();
8170 this.maskEl.right.setStyle('position', 'absolute');
8171 this.maskEl.right.setStyle('z-index', zIndex);
8172 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8173 this.maskEl.right.setLeft(box.right + this.padding);
8174 this.maskEl.right.setTop(box.y - this.padding);
8175 this.maskEl.right.show();
8177 this.toolTip.bindEl = this.target.el;
8179 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8181 var tip = this.target.blankText;
8183 if(this.target.getValue() !== '' ) {
8185 if (this.target.invalidText.length) {
8186 tip = this.target.invalidText;
8187 } else if (this.target.regexText.length){
8188 tip = this.target.regexText;
8192 this.toolTip.show(tip);
8194 this.intervalID = window.setInterval(function() {
8195 Roo.bootstrap.Form.popover.unmask();
8198 window.onwheel = function(){ return false;};
8200 (function(){ this.isMasked = true; }).defer(500, this);
8206 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8210 this.maskEl.top.setStyle('position', 'absolute');
8211 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8212 this.maskEl.top.hide();
8214 this.maskEl.left.setStyle('position', 'absolute');
8215 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8216 this.maskEl.left.hide();
8218 this.maskEl.bottom.setStyle('position', 'absolute');
8219 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8220 this.maskEl.bottom.hide();
8222 this.maskEl.right.setStyle('position', 'absolute');
8223 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8224 this.maskEl.right.hide();
8226 this.toolTip.hide();
8228 this.toolTip.el.hide();
8230 window.onwheel = function(){ return true;};
8232 if(this.intervalID){
8233 window.clearInterval(this.intervalID);
8234 this.intervalID = false;
8237 this.isMasked = false;
8247 * Ext JS Library 1.1.1
8248 * Copyright(c) 2006-2007, Ext JS, LLC.
8250 * Originally Released Under LGPL - original licence link has changed is not relivant.
8253 * <script type="text/javascript">
8256 * @class Roo.form.VTypes
8257 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8260 Roo.form.VTypes = function(){
8261 // closure these in so they are only created once.
8262 var alpha = /^[a-zA-Z_]+$/;
8263 var alphanum = /^[a-zA-Z0-9_]+$/;
8264 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8265 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8267 // All these messages and functions are configurable
8270 * The function used to validate email addresses
8271 * @param {String} value The email address
8273 'email' : function(v){
8274 return email.test(v);
8277 * The error text to display when the email validation function returns false
8280 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8282 * The keystroke filter mask to be applied on email input
8285 'emailMask' : /[a-z0-9_\.\-@]/i,
8288 * The function used to validate URLs
8289 * @param {String} value The URL
8291 'url' : function(v){
8295 * The error text to display when the url validation function returns false
8298 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8301 * The function used to validate alpha values
8302 * @param {String} value The value
8304 'alpha' : function(v){
8305 return alpha.test(v);
8308 * The error text to display when the alpha validation function returns false
8311 'alphaText' : 'This field should only contain letters and _',
8313 * The keystroke filter mask to be applied on alpha input
8316 'alphaMask' : /[a-z_]/i,
8319 * The function used to validate alphanumeric values
8320 * @param {String} value The value
8322 'alphanum' : function(v){
8323 return alphanum.test(v);
8326 * The error text to display when the alphanumeric validation function returns false
8329 'alphanumText' : 'This field should only contain letters, numbers and _',
8331 * The keystroke filter mask to be applied on alphanumeric input
8334 'alphanumMask' : /[a-z0-9_]/i
8344 * @class Roo.bootstrap.Input
8345 * @extends Roo.bootstrap.Component
8346 * Bootstrap Input class
8347 * @cfg {Boolean} disabled is it disabled
8348 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8349 * @cfg {String} name name of the input
8350 * @cfg {string} fieldLabel - the label associated
8351 * @cfg {string} placeholder - placeholder to put in text.
8352 * @cfg {string} before - input group add on before
8353 * @cfg {string} after - input group add on after
8354 * @cfg {string} size - (lg|sm) or leave empty..
8355 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8356 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8357 * @cfg {Number} md colspan out of 12 for computer-sized screens
8358 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8359 * @cfg {string} value default value of the input
8360 * @cfg {Number} labelWidth set the width of label
8361 * @cfg {Number} labellg set the width of label (1-12)
8362 * @cfg {Number} labelmd set the width of label (1-12)
8363 * @cfg {Number} labelsm set the width of label (1-12)
8364 * @cfg {Number} labelxs set the width of label (1-12)
8365 * @cfg {String} labelAlign (top|left)
8366 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8367 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8368 * @cfg {String} indicatorpos (left|right) default left
8370 * @cfg {String} align (left|center|right) Default left
8371 * @cfg {Boolean} forceFeedback (true|false) Default false
8377 * Create a new Input
8378 * @param {Object} config The config object
8381 Roo.bootstrap.Input = function(config){
8383 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8388 * Fires when this field receives input focus.
8389 * @param {Roo.form.Field} this
8394 * Fires when this field loses input focus.
8395 * @param {Roo.form.Field} this
8400 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8401 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8402 * @param {Roo.form.Field} this
8403 * @param {Roo.EventObject} e The event object
8408 * Fires just before the field blurs if the field value has changed.
8409 * @param {Roo.form.Field} this
8410 * @param {Mixed} newValue The new value
8411 * @param {Mixed} oldValue The original value
8416 * Fires after the field has been marked as invalid.
8417 * @param {Roo.form.Field} this
8418 * @param {String} msg The validation message
8423 * Fires after the field has been validated with no errors.
8424 * @param {Roo.form.Field} this
8429 * Fires after the key up
8430 * @param {Roo.form.Field} this
8431 * @param {Roo.EventObject} e The event Object
8437 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8439 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8440 automatic validation (defaults to "keyup").
8442 validationEvent : "keyup",
8444 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8446 validateOnBlur : true,
8448 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8450 validationDelay : 250,
8452 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8454 focusClass : "x-form-focus", // not needed???
8458 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8460 invalidClass : "has-warning",
8463 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8465 validClass : "has-success",
8468 * @cfg {Boolean} hasFeedback (true|false) default true
8473 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8475 invalidFeedbackClass : "glyphicon-warning-sign",
8478 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8480 validFeedbackClass : "glyphicon-ok",
8483 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8485 selectOnFocus : false,
8488 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8492 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8497 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8499 disableKeyFilter : false,
8502 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8506 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8510 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8512 blankText : "Please complete this mandatory field",
8515 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8519 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8521 maxLength : Number.MAX_VALUE,
8523 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8525 minLengthText : "The minimum length for this field is {0}",
8527 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8529 maxLengthText : "The maximum length for this field is {0}",
8533 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8534 * If available, this function will be called only after the basic validators all return true, and will be passed the
8535 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8539 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8540 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8541 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8545 * @cfg {String} regexText -- Depricated - use Invalid Text
8550 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8556 autocomplete: false,
8575 formatedValue : false,
8576 forceFeedback : false,
8578 indicatorpos : 'left',
8585 parentLabelAlign : function()
8588 while (parent.parent()) {
8589 parent = parent.parent();
8590 if (typeof(parent.labelAlign) !='undefined') {
8591 return parent.labelAlign;
8598 getAutoCreate : function()
8600 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8606 if(this.inputType != 'hidden'){
8607 cfg.cls = 'form-group' //input-group
8613 type : this.inputType,
8615 cls : 'form-control',
8616 placeholder : this.placeholder || '',
8617 autocomplete : this.autocomplete || 'new-password'
8621 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8624 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8625 input.maxLength = this.maxLength;
8628 if (this.disabled) {
8629 input.disabled=true;
8632 if (this.readOnly) {
8633 input.readonly=true;
8637 input.name = this.name;
8641 input.cls += ' input-' + this.size;
8645 ['xs','sm','md','lg'].map(function(size){
8646 if (settings[size]) {
8647 cfg.cls += ' col-' + size + '-' + settings[size];
8651 var inputblock = input;
8655 cls: 'glyphicon form-control-feedback'
8658 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8661 cls : 'has-feedback',
8669 if (this.before || this.after) {
8672 cls : 'input-group',
8676 if (this.before && typeof(this.before) == 'string') {
8678 inputblock.cn.push({
8680 cls : 'roo-input-before input-group-addon',
8684 if (this.before && typeof(this.before) == 'object') {
8685 this.before = Roo.factory(this.before);
8687 inputblock.cn.push({
8689 cls : 'roo-input-before input-group-' +
8690 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8694 inputblock.cn.push(input);
8696 if (this.after && typeof(this.after) == 'string') {
8697 inputblock.cn.push({
8699 cls : 'roo-input-after input-group-addon',
8703 if (this.after && typeof(this.after) == 'object') {
8704 this.after = Roo.factory(this.after);
8706 inputblock.cn.push({
8708 cls : 'roo-input-after input-group-' +
8709 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8713 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8714 inputblock.cls += ' has-feedback';
8715 inputblock.cn.push(feedback);
8719 if (align ==='left' && this.fieldLabel.length) {
8721 cfg.cls += ' roo-form-group-label-left';
8726 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8727 tooltip : 'This field is required'
8732 cls : 'control-label',
8733 html : this.fieldLabel
8744 var labelCfg = cfg.cn[1];
8745 var contentCfg = cfg.cn[2];
8747 if(this.indicatorpos == 'right'){
8752 cls : 'control-label',
8756 html : this.fieldLabel
8760 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8761 tooltip : 'This field is required'
8774 labelCfg = cfg.cn[0];
8775 contentCfg = cfg.cn[1];
8779 if(this.labelWidth > 12){
8780 labelCfg.style = "width: " + this.labelWidth + 'px';
8783 if(this.labelWidth < 13 && this.labelmd == 0){
8784 this.labelmd = this.labelWidth;
8787 if(this.labellg > 0){
8788 labelCfg.cls += ' col-lg-' + this.labellg;
8789 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8792 if(this.labelmd > 0){
8793 labelCfg.cls += ' col-md-' + this.labelmd;
8794 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8797 if(this.labelsm > 0){
8798 labelCfg.cls += ' col-sm-' + this.labelsm;
8799 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8802 if(this.labelxs > 0){
8803 labelCfg.cls += ' col-xs-' + this.labelxs;
8804 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8808 } else if ( this.fieldLabel.length) {
8813 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8814 tooltip : 'This field is required'
8818 //cls : 'input-group-addon',
8819 html : this.fieldLabel
8827 if(this.indicatorpos == 'right'){
8832 //cls : 'input-group-addon',
8833 html : this.fieldLabel
8838 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8839 tooltip : 'This field is required'
8859 if (this.parentType === 'Navbar' && this.parent().bar) {
8860 cfg.cls += ' navbar-form';
8863 if (this.parentType === 'NavGroup') {
8864 cfg.cls += ' navbar-form';
8872 * return the real input element.
8874 inputEl: function ()
8876 return this.el.select('input.form-control',true).first();
8879 tooltipEl : function()
8881 return this.inputEl();
8884 indicatorEl : function()
8886 var indicator = this.el.select('i.roo-required-indicator',true).first();
8896 setDisabled : function(v)
8898 var i = this.inputEl().dom;
8900 i.removeAttribute('disabled');
8904 i.setAttribute('disabled','true');
8906 initEvents : function()
8909 this.inputEl().on("keydown" , this.fireKey, this);
8910 this.inputEl().on("focus", this.onFocus, this);
8911 this.inputEl().on("blur", this.onBlur, this);
8913 this.inputEl().relayEvent('keyup', this);
8915 this.indicator = this.indicatorEl();
8918 this.indicator.addClass('invisible');
8922 // reference to original value for reset
8923 this.originalValue = this.getValue();
8924 //Roo.form.TextField.superclass.initEvents.call(this);
8925 if(this.validationEvent == 'keyup'){
8926 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8927 this.inputEl().on('keyup', this.filterValidation, this);
8929 else if(this.validationEvent !== false){
8930 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8933 if(this.selectOnFocus){
8934 this.on("focus", this.preFocus, this);
8937 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8938 this.inputEl().on("keypress", this.filterKeys, this);
8940 this.inputEl().relayEvent('keypress', this);
8943 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8944 this.el.on("click", this.autoSize, this);
8947 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8948 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8951 if (typeof(this.before) == 'object') {
8952 this.before.render(this.el.select('.roo-input-before',true).first());
8954 if (typeof(this.after) == 'object') {
8955 this.after.render(this.el.select('.roo-input-after',true).first());
8960 filterValidation : function(e){
8961 if(!e.isNavKeyPress()){
8962 this.validationTask.delay(this.validationDelay);
8966 * Validates the field value
8967 * @return {Boolean} True if the value is valid, else false
8969 validate : function(){
8970 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8971 if(this.disabled || this.validateValue(this.getRawValue())){
8982 * Validates a value according to the field's validation rules and marks the field as invalid
8983 * if the validation fails
8984 * @param {Mixed} value The value to validate
8985 * @return {Boolean} True if the value is valid, else false
8987 validateValue : function(value){
8988 if(value.length < 1) { // if it's blank
8989 if(this.allowBlank){
8992 return this.inputEl().hasClass('hide') ? true : false;
8995 if(value.length < this.minLength){
8998 if(value.length > this.maxLength){
9002 var vt = Roo.form.VTypes;
9003 if(!vt[this.vtype](value, this)){
9007 if(typeof this.validator == "function"){
9008 var msg = this.validator(value);
9012 if (typeof(msg) == 'string') {
9013 this.invalidText = msg;
9017 if(this.regex && !this.regex.test(value)){
9027 fireKey : function(e){
9028 //Roo.log('field ' + e.getKey());
9029 if(e.isNavKeyPress()){
9030 this.fireEvent("specialkey", this, e);
9033 focus : function (selectText){
9035 this.inputEl().focus();
9036 if(selectText === true){
9037 this.inputEl().dom.select();
9043 onFocus : function(){
9044 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9045 // this.el.addClass(this.focusClass);
9048 this.hasFocus = true;
9049 this.startValue = this.getValue();
9050 this.fireEvent("focus", this);
9054 beforeBlur : Roo.emptyFn,
9058 onBlur : function(){
9060 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9061 //this.el.removeClass(this.focusClass);
9063 this.hasFocus = false;
9064 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9067 var v = this.getValue();
9068 if(String(v) !== String(this.startValue)){
9069 this.fireEvent('change', this, v, this.startValue);
9071 this.fireEvent("blur", this);
9075 * Resets the current field value to the originally loaded value and clears any validation messages
9078 this.setValue(this.originalValue);
9082 * Returns the name of the field
9083 * @return {Mixed} name The name field
9085 getName: function(){
9089 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9090 * @return {Mixed} value The field value
9092 getValue : function(){
9094 var v = this.inputEl().getValue();
9099 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9100 * @return {Mixed} value The field value
9102 getRawValue : function(){
9103 var v = this.inputEl().getValue();
9109 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9110 * @param {Mixed} value The value to set
9112 setRawValue : function(v){
9113 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9116 selectText : function(start, end){
9117 var v = this.getRawValue();
9119 start = start === undefined ? 0 : start;
9120 end = end === undefined ? v.length : end;
9121 var d = this.inputEl().dom;
9122 if(d.setSelectionRange){
9123 d.setSelectionRange(start, end);
9124 }else if(d.createTextRange){
9125 var range = d.createTextRange();
9126 range.moveStart("character", start);
9127 range.moveEnd("character", v.length-end);
9134 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9135 * @param {Mixed} value The value to set
9137 setValue : function(v){
9140 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9146 processValue : function(value){
9147 if(this.stripCharsRe){
9148 var newValue = value.replace(this.stripCharsRe, '');
9149 if(newValue !== value){
9150 this.setRawValue(newValue);
9157 preFocus : function(){
9159 if(this.selectOnFocus){
9160 this.inputEl().dom.select();
9163 filterKeys : function(e){
9165 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9168 var c = e.getCharCode(), cc = String.fromCharCode(c);
9169 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9172 if(!this.maskRe.test(cc)){
9177 * Clear any invalid styles/messages for this field
9179 clearInvalid : function(){
9181 if(!this.el || this.preventMark){ // not rendered
9186 this.el.removeClass(this.invalidClass);
9188 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9190 var feedback = this.el.select('.form-control-feedback', true).first();
9193 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9198 this.fireEvent('valid', this);
9202 * Mark this field as valid
9204 markValid : function()
9206 if(!this.el || this.preventMark){ // not rendered...
9210 this.el.removeClass([this.invalidClass, this.validClass]);
9212 var feedback = this.el.select('.form-control-feedback', true).first();
9215 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9222 if(this.allowBlank && !this.getRawValue().length){
9227 this.indicator.removeClass('visible');
9228 this.indicator.addClass('invisible');
9231 this.el.addClass(this.validClass);
9233 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9235 var feedback = this.el.select('.form-control-feedback', true).first();
9238 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9239 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9244 this.fireEvent('valid', this);
9248 * Mark this field as invalid
9249 * @param {String} msg The validation message
9251 markInvalid : function(msg)
9253 if(!this.el || this.preventMark){ // not rendered
9257 this.el.removeClass([this.invalidClass, this.validClass]);
9259 var feedback = this.el.select('.form-control-feedback', true).first();
9262 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9269 if(this.allowBlank && !this.getRawValue().length){
9274 this.indicator.removeClass('invisible');
9275 this.indicator.addClass('visible');
9278 this.el.addClass(this.invalidClass);
9280 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9282 var feedback = this.el.select('.form-control-feedback', true).first();
9285 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9287 if(this.getValue().length || this.forceFeedback){
9288 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9295 this.fireEvent('invalid', this, msg);
9298 SafariOnKeyDown : function(event)
9300 // this is a workaround for a password hang bug on chrome/ webkit.
9301 if (this.inputEl().dom.type != 'password') {
9305 var isSelectAll = false;
9307 if(this.inputEl().dom.selectionEnd > 0){
9308 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9310 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9311 event.preventDefault();
9316 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9318 event.preventDefault();
9319 // this is very hacky as keydown always get's upper case.
9321 var cc = String.fromCharCode(event.getCharCode());
9322 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9326 adjustWidth : function(tag, w){
9327 tag = tag.toLowerCase();
9328 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9329 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9333 if(tag == 'textarea'){
9336 }else if(Roo.isOpera){
9340 if(tag == 'textarea'){
9348 setFieldLabel : function(v)
9350 this.fieldLabel = v;
9353 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9367 * @class Roo.bootstrap.TextArea
9368 * @extends Roo.bootstrap.Input
9369 * Bootstrap TextArea class
9370 * @cfg {Number} cols Specifies the visible width of a text area
9371 * @cfg {Number} rows Specifies the visible number of lines in a text area
9372 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9373 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9374 * @cfg {string} html text
9377 * Create a new TextArea
9378 * @param {Object} config The config object
9381 Roo.bootstrap.TextArea = function(config){
9382 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9386 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9396 getAutoCreate : function(){
9398 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9404 if(this.inputType != 'hidden'){
9405 cfg.cls = 'form-group' //input-group
9413 value : this.value || '',
9414 html: this.html || '',
9415 cls : 'form-control',
9416 placeholder : this.placeholder || ''
9420 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9421 input.maxLength = this.maxLength;
9425 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9429 input.cols = this.cols;
9432 if (this.readOnly) {
9433 input.readonly = true;
9437 input.name = this.name;
9441 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9445 ['xs','sm','md','lg'].map(function(size){
9446 if (settings[size]) {
9447 cfg.cls += ' col-' + size + '-' + settings[size];
9451 var inputblock = input;
9453 if(this.hasFeedback && !this.allowBlank){
9457 cls: 'glyphicon form-control-feedback'
9461 cls : 'has-feedback',
9470 if (this.before || this.after) {
9473 cls : 'input-group',
9477 inputblock.cn.push({
9479 cls : 'input-group-addon',
9484 inputblock.cn.push(input);
9486 if(this.hasFeedback && !this.allowBlank){
9487 inputblock.cls += ' has-feedback';
9488 inputblock.cn.push(feedback);
9492 inputblock.cn.push({
9494 cls : 'input-group-addon',
9501 if (align ==='left' && this.fieldLabel.length) {
9506 cls : 'control-label',
9507 html : this.fieldLabel
9518 if(this.labelWidth > 12){
9519 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9522 if(this.labelWidth < 13 && this.labelmd == 0){
9523 this.labelmd = this.labelWidth;
9526 if(this.labellg > 0){
9527 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9528 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9531 if(this.labelmd > 0){
9532 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9533 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9536 if(this.labelsm > 0){
9537 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9538 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9541 if(this.labelxs > 0){
9542 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9543 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9546 } else if ( this.fieldLabel.length) {
9551 //cls : 'input-group-addon',
9552 html : this.fieldLabel
9570 if (this.disabled) {
9571 input.disabled=true;
9578 * return the real textarea element.
9580 inputEl: function ()
9582 return this.el.select('textarea.form-control',true).first();
9586 * Clear any invalid styles/messages for this field
9588 clearInvalid : function()
9591 if(!this.el || this.preventMark){ // not rendered
9595 var label = this.el.select('label', true).first();
9596 var icon = this.el.select('i.fa-star', true).first();
9602 this.el.removeClass(this.invalidClass);
9604 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9606 var feedback = this.el.select('.form-control-feedback', true).first();
9609 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9614 this.fireEvent('valid', this);
9618 * Mark this field as valid
9620 markValid : function()
9622 if(!this.el || this.preventMark){ // not rendered
9626 this.el.removeClass([this.invalidClass, this.validClass]);
9628 var feedback = this.el.select('.form-control-feedback', true).first();
9631 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9634 if(this.disabled || this.allowBlank){
9638 var label = this.el.select('label', true).first();
9639 var icon = this.el.select('i.fa-star', true).first();
9645 this.el.addClass(this.validClass);
9647 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9649 var feedback = this.el.select('.form-control-feedback', true).first();
9652 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9653 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9658 this.fireEvent('valid', this);
9662 * Mark this field as invalid
9663 * @param {String} msg The validation message
9665 markInvalid : function(msg)
9667 if(!this.el || this.preventMark){ // not rendered
9671 this.el.removeClass([this.invalidClass, this.validClass]);
9673 var feedback = this.el.select('.form-control-feedback', true).first();
9676 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9679 if(this.disabled || this.allowBlank){
9683 var label = this.el.select('label', true).first();
9684 var icon = this.el.select('i.fa-star', true).first();
9686 if(!this.getValue().length && label && !icon){
9687 this.el.createChild({
9689 cls : 'text-danger fa fa-lg fa-star',
9690 tooltip : 'This field is required',
9691 style : 'margin-right:5px;'
9695 this.el.addClass(this.invalidClass);
9697 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9699 var feedback = this.el.select('.form-control-feedback', true).first();
9702 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9704 if(this.getValue().length || this.forceFeedback){
9705 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9712 this.fireEvent('invalid', this, msg);
9720 * trigger field - base class for combo..
9725 * @class Roo.bootstrap.TriggerField
9726 * @extends Roo.bootstrap.Input
9727 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9728 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9729 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9730 * for which you can provide a custom implementation. For example:
9732 var trigger = new Roo.bootstrap.TriggerField();
9733 trigger.onTriggerClick = myTriggerFn;
9734 trigger.applyTo('my-field');
9737 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9738 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9739 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9740 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9741 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9744 * Create a new TriggerField.
9745 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9746 * to the base TextField)
9748 Roo.bootstrap.TriggerField = function(config){
9749 this.mimicing = false;
9750 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9753 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9755 * @cfg {String} triggerClass A CSS class to apply to the trigger
9758 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9763 * @cfg {Boolean} removable (true|false) special filter default false
9767 /** @cfg {Boolean} grow @hide */
9768 /** @cfg {Number} growMin @hide */
9769 /** @cfg {Number} growMax @hide */
9775 autoSize: Roo.emptyFn,
9782 actionMode : 'wrap',
9787 getAutoCreate : function(){
9789 var align = this.labelAlign || this.parentLabelAlign();
9794 cls: 'form-group' //input-group
9801 type : this.inputType,
9802 cls : 'form-control',
9803 autocomplete: 'new-password',
9804 placeholder : this.placeholder || ''
9808 input.name = this.name;
9811 input.cls += ' input-' + this.size;
9814 if (this.disabled) {
9815 input.disabled=true;
9818 var inputblock = input;
9820 if(this.hasFeedback && !this.allowBlank){
9824 cls: 'glyphicon form-control-feedback'
9827 if(this.removable && !this.editable && !this.tickable){
9829 cls : 'has-feedback',
9835 cls : 'roo-combo-removable-btn close'
9842 cls : 'has-feedback',
9851 if(this.removable && !this.editable && !this.tickable){
9853 cls : 'roo-removable',
9859 cls : 'roo-combo-removable-btn close'
9866 if (this.before || this.after) {
9869 cls : 'input-group',
9873 inputblock.cn.push({
9875 cls : 'input-group-addon',
9880 inputblock.cn.push(input);
9882 if(this.hasFeedback && !this.allowBlank){
9883 inputblock.cls += ' has-feedback';
9884 inputblock.cn.push(feedback);
9888 inputblock.cn.push({
9890 cls : 'input-group-addon',
9903 cls: 'form-hidden-field'
9917 cls: 'form-hidden-field'
9921 cls: 'roo-select2-choices',
9925 cls: 'roo-select2-search-field',
9938 cls: 'roo-select2-container input-group',
9943 // cls: 'typeahead typeahead-long dropdown-menu',
9944 // style: 'display:none'
9949 if(!this.multiple && this.showToggleBtn){
9955 if (this.caret != false) {
9958 cls: 'fa fa-' + this.caret
9965 cls : 'input-group-addon btn dropdown-toggle',
9970 cls: 'combobox-clear',
9984 combobox.cls += ' roo-select2-container-multi';
9987 if (align ==='left' && this.fieldLabel.length) {
9989 cfg.cls += ' roo-form-group-label-left';
9994 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9995 tooltip : 'This field is required'
10000 cls : 'control-label',
10001 html : this.fieldLabel
10013 var labelCfg = cfg.cn[1];
10014 var contentCfg = cfg.cn[2];
10016 if(this.indicatorpos == 'right'){
10021 cls : 'control-label',
10025 html : this.fieldLabel
10029 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10030 tooltip : 'This field is required'
10043 labelCfg = cfg.cn[0];
10044 contentCfg = cfg.cn[1];
10047 if(this.labelWidth > 12){
10048 labelCfg.style = "width: " + this.labelWidth + 'px';
10051 if(this.labelWidth < 13 && this.labelmd == 0){
10052 this.labelmd = this.labelWidth;
10055 if(this.labellg > 0){
10056 labelCfg.cls += ' col-lg-' + this.labellg;
10057 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10060 if(this.labelmd > 0){
10061 labelCfg.cls += ' col-md-' + this.labelmd;
10062 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10065 if(this.labelsm > 0){
10066 labelCfg.cls += ' col-sm-' + this.labelsm;
10067 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10070 if(this.labelxs > 0){
10071 labelCfg.cls += ' col-xs-' + this.labelxs;
10072 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10075 } else if ( this.fieldLabel.length) {
10076 // Roo.log(" label");
10080 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10081 tooltip : 'This field is required'
10085 //cls : 'input-group-addon',
10086 html : this.fieldLabel
10094 if(this.indicatorpos == 'right'){
10102 html : this.fieldLabel
10106 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10107 tooltip : 'This field is required'
10120 // Roo.log(" no label && no align");
10127 ['xs','sm','md','lg'].map(function(size){
10128 if (settings[size]) {
10129 cfg.cls += ' col-' + size + '-' + settings[size];
10140 onResize : function(w, h){
10141 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10142 // if(typeof w == 'number'){
10143 // var x = w - this.trigger.getWidth();
10144 // this.inputEl().setWidth(this.adjustWidth('input', x));
10145 // this.trigger.setStyle('left', x+'px');
10150 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10153 getResizeEl : function(){
10154 return this.inputEl();
10158 getPositionEl : function(){
10159 return this.inputEl();
10163 alignErrorIcon : function(){
10164 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10168 initEvents : function(){
10172 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10173 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10174 if(!this.multiple && this.showToggleBtn){
10175 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10176 if(this.hideTrigger){
10177 this.trigger.setDisplayed(false);
10179 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10183 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10186 if(this.removable && !this.editable && !this.tickable){
10187 var close = this.closeTriggerEl();
10190 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10191 close.on('click', this.removeBtnClick, this, close);
10195 //this.trigger.addClassOnOver('x-form-trigger-over');
10196 //this.trigger.addClassOnClick('x-form-trigger-click');
10199 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10203 closeTriggerEl : function()
10205 var close = this.el.select('.roo-combo-removable-btn', true).first();
10206 return close ? close : false;
10209 removeBtnClick : function(e, h, el)
10211 e.preventDefault();
10213 if(this.fireEvent("remove", this) !== false){
10215 this.fireEvent("afterremove", this)
10219 createList : function()
10221 this.list = Roo.get(document.body).createChild({
10223 cls: 'typeahead typeahead-long dropdown-menu',
10224 style: 'display:none'
10227 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10232 initTrigger : function(){
10237 onDestroy : function(){
10239 this.trigger.removeAllListeners();
10240 // this.trigger.remove();
10243 // this.wrap.remove();
10245 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10249 onFocus : function(){
10250 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10252 if(!this.mimicing){
10253 this.wrap.addClass('x-trigger-wrap-focus');
10254 this.mimicing = true;
10255 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10256 if(this.monitorTab){
10257 this.el.on("keydown", this.checkTab, this);
10264 checkTab : function(e){
10265 if(e.getKey() == e.TAB){
10266 this.triggerBlur();
10271 onBlur : function(){
10276 mimicBlur : function(e, t){
10278 if(!this.wrap.contains(t) && this.validateBlur()){
10279 this.triggerBlur();
10285 triggerBlur : function(){
10286 this.mimicing = false;
10287 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10288 if(this.monitorTab){
10289 this.el.un("keydown", this.checkTab, this);
10291 //this.wrap.removeClass('x-trigger-wrap-focus');
10292 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10296 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10297 validateBlur : function(e, t){
10302 onDisable : function(){
10303 this.inputEl().dom.disabled = true;
10304 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10306 // this.wrap.addClass('x-item-disabled');
10311 onEnable : function(){
10312 this.inputEl().dom.disabled = false;
10313 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10315 // this.el.removeClass('x-item-disabled');
10320 onShow : function(){
10321 var ae = this.getActionEl();
10324 ae.dom.style.display = '';
10325 ae.dom.style.visibility = 'visible';
10331 onHide : function(){
10332 var ae = this.getActionEl();
10333 ae.dom.style.display = 'none';
10337 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10338 * by an implementing function.
10340 * @param {EventObject} e
10342 onTriggerClick : Roo.emptyFn
10346 * Ext JS Library 1.1.1
10347 * Copyright(c) 2006-2007, Ext JS, LLC.
10349 * Originally Released Under LGPL - original licence link has changed is not relivant.
10352 * <script type="text/javascript">
10357 * @class Roo.data.SortTypes
10359 * Defines the default sorting (casting?) comparison functions used when sorting data.
10361 Roo.data.SortTypes = {
10363 * Default sort that does nothing
10364 * @param {Mixed} s The value being converted
10365 * @return {Mixed} The comparison value
10367 none : function(s){
10372 * The regular expression used to strip tags
10376 stripTagsRE : /<\/?[^>]+>/gi,
10379 * Strips all HTML tags to sort on text only
10380 * @param {Mixed} s The value being converted
10381 * @return {String} The comparison value
10383 asText : function(s){
10384 return String(s).replace(this.stripTagsRE, "");
10388 * Strips all HTML tags to sort on text only - Case insensitive
10389 * @param {Mixed} s The value being converted
10390 * @return {String} The comparison value
10392 asUCText : function(s){
10393 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10397 * Case insensitive string
10398 * @param {Mixed} s The value being converted
10399 * @return {String} The comparison value
10401 asUCString : function(s) {
10402 return String(s).toUpperCase();
10407 * @param {Mixed} s The value being converted
10408 * @return {Number} The comparison value
10410 asDate : function(s) {
10414 if(s instanceof Date){
10415 return s.getTime();
10417 return Date.parse(String(s));
10422 * @param {Mixed} s The value being converted
10423 * @return {Float} The comparison value
10425 asFloat : function(s) {
10426 var val = parseFloat(String(s).replace(/,/g, ""));
10435 * @param {Mixed} s The value being converted
10436 * @return {Number} The comparison value
10438 asInt : function(s) {
10439 var val = parseInt(String(s).replace(/,/g, ""));
10447 * Ext JS Library 1.1.1
10448 * Copyright(c) 2006-2007, Ext JS, LLC.
10450 * Originally Released Under LGPL - original licence link has changed is not relivant.
10453 * <script type="text/javascript">
10457 * @class Roo.data.Record
10458 * Instances of this class encapsulate both record <em>definition</em> information, and record
10459 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10460 * to access Records cached in an {@link Roo.data.Store} object.<br>
10462 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10463 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10466 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10468 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10469 * {@link #create}. The parameters are the same.
10470 * @param {Array} data An associative Array of data values keyed by the field name.
10471 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10472 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10473 * not specified an integer id is generated.
10475 Roo.data.Record = function(data, id){
10476 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10481 * Generate a constructor for a specific record layout.
10482 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10483 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10484 * Each field definition object may contain the following properties: <ul>
10485 * <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,
10486 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10487 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10488 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10489 * is being used, then this is a string containing the javascript expression to reference the data relative to
10490 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10491 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10492 * this may be omitted.</p></li>
10493 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10494 * <ul><li>auto (Default, implies no conversion)</li>
10499 * <li>date</li></ul></p></li>
10500 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10501 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10502 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10503 * by the Reader into an object that will be stored in the Record. It is passed the
10504 * following parameters:<ul>
10505 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10507 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10509 * <br>usage:<br><pre><code>
10510 var TopicRecord = Roo.data.Record.create(
10511 {name: 'title', mapping: 'topic_title'},
10512 {name: 'author', mapping: 'username'},
10513 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10514 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10515 {name: 'lastPoster', mapping: 'user2'},
10516 {name: 'excerpt', mapping: 'post_text'}
10519 var myNewRecord = new TopicRecord({
10520 title: 'Do my job please',
10523 lastPost: new Date(),
10524 lastPoster: 'Animal',
10525 excerpt: 'No way dude!'
10527 myStore.add(myNewRecord);
10532 Roo.data.Record.create = function(o){
10533 var f = function(){
10534 f.superclass.constructor.apply(this, arguments);
10536 Roo.extend(f, Roo.data.Record);
10537 var p = f.prototype;
10538 p.fields = new Roo.util.MixedCollection(false, function(field){
10541 for(var i = 0, len = o.length; i < len; i++){
10542 p.fields.add(new Roo.data.Field(o[i]));
10544 f.getField = function(name){
10545 return p.fields.get(name);
10550 Roo.data.Record.AUTO_ID = 1000;
10551 Roo.data.Record.EDIT = 'edit';
10552 Roo.data.Record.REJECT = 'reject';
10553 Roo.data.Record.COMMIT = 'commit';
10555 Roo.data.Record.prototype = {
10557 * Readonly flag - true if this record has been modified.
10566 join : function(store){
10567 this.store = store;
10571 * Set the named field to the specified value.
10572 * @param {String} name The name of the field to set.
10573 * @param {Object} value The value to set the field to.
10575 set : function(name, value){
10576 if(this.data[name] == value){
10580 if(!this.modified){
10581 this.modified = {};
10583 if(typeof this.modified[name] == 'undefined'){
10584 this.modified[name] = this.data[name];
10586 this.data[name] = value;
10587 if(!this.editing && this.store){
10588 this.store.afterEdit(this);
10593 * Get the value of the named field.
10594 * @param {String} name The name of the field to get the value of.
10595 * @return {Object} The value of the field.
10597 get : function(name){
10598 return this.data[name];
10602 beginEdit : function(){
10603 this.editing = true;
10604 this.modified = {};
10608 cancelEdit : function(){
10609 this.editing = false;
10610 delete this.modified;
10614 endEdit : function(){
10615 this.editing = false;
10616 if(this.dirty && this.store){
10617 this.store.afterEdit(this);
10622 * Usually called by the {@link Roo.data.Store} which owns the Record.
10623 * Rejects all changes made to the Record since either creation, or the last commit operation.
10624 * Modified fields are reverted to their original values.
10626 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10627 * of reject operations.
10629 reject : function(){
10630 var m = this.modified;
10632 if(typeof m[n] != "function"){
10633 this.data[n] = m[n];
10636 this.dirty = false;
10637 delete this.modified;
10638 this.editing = false;
10640 this.store.afterReject(this);
10645 * Usually called by the {@link Roo.data.Store} which owns the Record.
10646 * Commits all changes made to the Record since either creation, or the last commit operation.
10648 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10649 * of commit operations.
10651 commit : function(){
10652 this.dirty = false;
10653 delete this.modified;
10654 this.editing = false;
10656 this.store.afterCommit(this);
10661 hasError : function(){
10662 return this.error != null;
10666 clearError : function(){
10671 * Creates a copy of this record.
10672 * @param {String} id (optional) A new record id if you don't want to use this record's id
10675 copy : function(newId) {
10676 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10680 * Ext JS Library 1.1.1
10681 * Copyright(c) 2006-2007, Ext JS, LLC.
10683 * Originally Released Under LGPL - original licence link has changed is not relivant.
10686 * <script type="text/javascript">
10692 * @class Roo.data.Store
10693 * @extends Roo.util.Observable
10694 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10695 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10697 * 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
10698 * has no knowledge of the format of the data returned by the Proxy.<br>
10700 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10701 * instances from the data object. These records are cached and made available through accessor functions.
10703 * Creates a new Store.
10704 * @param {Object} config A config object containing the objects needed for the Store to access data,
10705 * and read the data into Records.
10707 Roo.data.Store = function(config){
10708 this.data = new Roo.util.MixedCollection(false);
10709 this.data.getKey = function(o){
10712 this.baseParams = {};
10714 this.paramNames = {
10719 "multisort" : "_multisort"
10722 if(config && config.data){
10723 this.inlineData = config.data;
10724 delete config.data;
10727 Roo.apply(this, config);
10729 if(this.reader){ // reader passed
10730 this.reader = Roo.factory(this.reader, Roo.data);
10731 this.reader.xmodule = this.xmodule || false;
10732 if(!this.recordType){
10733 this.recordType = this.reader.recordType;
10735 if(this.reader.onMetaChange){
10736 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10740 if(this.recordType){
10741 this.fields = this.recordType.prototype.fields;
10743 this.modified = [];
10747 * @event datachanged
10748 * Fires when the data cache has changed, and a widget which is using this Store
10749 * as a Record cache should refresh its view.
10750 * @param {Store} this
10752 datachanged : true,
10754 * @event metachange
10755 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10756 * @param {Store} this
10757 * @param {Object} meta The JSON metadata
10762 * Fires when Records have been added to the Store
10763 * @param {Store} this
10764 * @param {Roo.data.Record[]} records The array of Records added
10765 * @param {Number} index The index at which the record(s) were added
10770 * Fires when a Record has been removed from the Store
10771 * @param {Store} this
10772 * @param {Roo.data.Record} record The Record that was removed
10773 * @param {Number} index The index at which the record was removed
10778 * Fires when a Record has been updated
10779 * @param {Store} this
10780 * @param {Roo.data.Record} record The Record that was updated
10781 * @param {String} operation The update operation being performed. Value may be one of:
10783 Roo.data.Record.EDIT
10784 Roo.data.Record.REJECT
10785 Roo.data.Record.COMMIT
10791 * Fires when the data cache has been cleared.
10792 * @param {Store} this
10796 * @event beforeload
10797 * Fires before a request is made for a new data object. If the beforeload handler returns false
10798 * the load action will be canceled.
10799 * @param {Store} this
10800 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10804 * @event beforeloadadd
10805 * Fires after a new set of Records has been loaded.
10806 * @param {Store} this
10807 * @param {Roo.data.Record[]} records The Records that were loaded
10808 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10810 beforeloadadd : true,
10813 * Fires after a new set of Records has been loaded, before they are added to the store.
10814 * @param {Store} this
10815 * @param {Roo.data.Record[]} records The Records that were loaded
10816 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10817 * @params {Object} return from reader
10821 * @event loadexception
10822 * Fires if an exception occurs in the Proxy during loading.
10823 * Called with the signature of the Proxy's "loadexception" event.
10824 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10827 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10828 * @param {Object} load options
10829 * @param {Object} jsonData from your request (normally this contains the Exception)
10831 loadexception : true
10835 this.proxy = Roo.factory(this.proxy, Roo.data);
10836 this.proxy.xmodule = this.xmodule || false;
10837 this.relayEvents(this.proxy, ["loadexception"]);
10839 this.sortToggle = {};
10840 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10842 Roo.data.Store.superclass.constructor.call(this);
10844 if(this.inlineData){
10845 this.loadData(this.inlineData);
10846 delete this.inlineData;
10850 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10852 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10853 * without a remote query - used by combo/forms at present.
10857 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10860 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10863 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10864 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10867 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10868 * on any HTTP request
10871 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10874 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10878 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10879 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10881 remoteSort : false,
10884 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10885 * loaded or when a record is removed. (defaults to false).
10887 pruneModifiedRecords : false,
10890 lastOptions : null,
10893 * Add Records to the Store and fires the add event.
10894 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10896 add : function(records){
10897 records = [].concat(records);
10898 for(var i = 0, len = records.length; i < len; i++){
10899 records[i].join(this);
10901 var index = this.data.length;
10902 this.data.addAll(records);
10903 this.fireEvent("add", this, records, index);
10907 * Remove a Record from the Store and fires the remove event.
10908 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10910 remove : function(record){
10911 var index = this.data.indexOf(record);
10912 this.data.removeAt(index);
10913 if(this.pruneModifiedRecords){
10914 this.modified.remove(record);
10916 this.fireEvent("remove", this, record, index);
10920 * Remove all Records from the Store and fires the clear event.
10922 removeAll : function(){
10924 if(this.pruneModifiedRecords){
10925 this.modified = [];
10927 this.fireEvent("clear", this);
10931 * Inserts Records to the Store at the given index and fires the add event.
10932 * @param {Number} index The start index at which to insert the passed Records.
10933 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10935 insert : function(index, records){
10936 records = [].concat(records);
10937 for(var i = 0, len = records.length; i < len; i++){
10938 this.data.insert(index, records[i]);
10939 records[i].join(this);
10941 this.fireEvent("add", this, records, index);
10945 * Get the index within the cache of the passed Record.
10946 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10947 * @return {Number} The index of the passed Record. Returns -1 if not found.
10949 indexOf : function(record){
10950 return this.data.indexOf(record);
10954 * Get the index within the cache of the Record with the passed id.
10955 * @param {String} id The id of the Record to find.
10956 * @return {Number} The index of the Record. Returns -1 if not found.
10958 indexOfId : function(id){
10959 return this.data.indexOfKey(id);
10963 * Get the Record with the specified id.
10964 * @param {String} id The id of the Record to find.
10965 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10967 getById : function(id){
10968 return this.data.key(id);
10972 * Get the Record at the specified index.
10973 * @param {Number} index The index of the Record to find.
10974 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10976 getAt : function(index){
10977 return this.data.itemAt(index);
10981 * Returns a range of Records between specified indices.
10982 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10983 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10984 * @return {Roo.data.Record[]} An array of Records
10986 getRange : function(start, end){
10987 return this.data.getRange(start, end);
10991 storeOptions : function(o){
10992 o = Roo.apply({}, o);
10995 this.lastOptions = o;
10999 * Loads the Record cache from the configured Proxy using the configured Reader.
11001 * If using remote paging, then the first load call must specify the <em>start</em>
11002 * and <em>limit</em> properties in the options.params property to establish the initial
11003 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11005 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11006 * and this call will return before the new data has been loaded. Perform any post-processing
11007 * in a callback function, or in a "load" event handler.</strong>
11009 * @param {Object} options An object containing properties which control loading options:<ul>
11010 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11011 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11012 * passed the following arguments:<ul>
11013 * <li>r : Roo.data.Record[]</li>
11014 * <li>options: Options object from the load call</li>
11015 * <li>success: Boolean success indicator</li></ul></li>
11016 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11017 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11020 load : function(options){
11021 options = options || {};
11022 if(this.fireEvent("beforeload", this, options) !== false){
11023 this.storeOptions(options);
11024 var p = Roo.apply(options.params || {}, this.baseParams);
11025 // if meta was not loaded from remote source.. try requesting it.
11026 if (!this.reader.metaFromRemote) {
11027 p._requestMeta = 1;
11029 if(this.sortInfo && this.remoteSort){
11030 var pn = this.paramNames;
11031 p[pn["sort"]] = this.sortInfo.field;
11032 p[pn["dir"]] = this.sortInfo.direction;
11034 if (this.multiSort) {
11035 var pn = this.paramNames;
11036 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11039 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11044 * Reloads the Record cache from the configured Proxy using the configured Reader and
11045 * the options from the last load operation performed.
11046 * @param {Object} options (optional) An object containing properties which may override the options
11047 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11048 * the most recently used options are reused).
11050 reload : function(options){
11051 this.load(Roo.applyIf(options||{}, this.lastOptions));
11055 // Called as a callback by the Reader during a load operation.
11056 loadRecords : function(o, options, success){
11057 if(!o || success === false){
11058 if(success !== false){
11059 this.fireEvent("load", this, [], options, o);
11061 if(options.callback){
11062 options.callback.call(options.scope || this, [], options, false);
11066 // if data returned failure - throw an exception.
11067 if (o.success === false) {
11068 // show a message if no listener is registered.
11069 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11070 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11072 // loadmask wil be hooked into this..
11073 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11076 var r = o.records, t = o.totalRecords || r.length;
11078 this.fireEvent("beforeloadadd", this, r, options, o);
11080 if(!options || options.add !== true){
11081 if(this.pruneModifiedRecords){
11082 this.modified = [];
11084 for(var i = 0, len = r.length; i < len; i++){
11088 this.data = this.snapshot;
11089 delete this.snapshot;
11092 this.data.addAll(r);
11093 this.totalLength = t;
11095 this.fireEvent("datachanged", this);
11097 this.totalLength = Math.max(t, this.data.length+r.length);
11101 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11103 var e = new Roo.data.Record({});
11105 e.set(this.parent.displayField, this.parent.emptyTitle);
11106 e.set(this.parent.valueField, '');
11111 this.fireEvent("load", this, r, options, o);
11112 if(options.callback){
11113 options.callback.call(options.scope || this, r, options, true);
11119 * Loads data from a passed data block. A Reader which understands the format of the data
11120 * must have been configured in the constructor.
11121 * @param {Object} data The data block from which to read the Records. The format of the data expected
11122 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11123 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11125 loadData : function(o, append){
11126 var r = this.reader.readRecords(o);
11127 this.loadRecords(r, {add: append}, true);
11131 * Gets the number of cached records.
11133 * <em>If using paging, this may not be the total size of the dataset. If the data object
11134 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11135 * the data set size</em>
11137 getCount : function(){
11138 return this.data.length || 0;
11142 * Gets the total number of records in the dataset as returned by the server.
11144 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11145 * the dataset size</em>
11147 getTotalCount : function(){
11148 return this.totalLength || 0;
11152 * Returns the sort state of the Store as an object with two properties:
11154 field {String} The name of the field by which the Records are sorted
11155 direction {String} The sort order, "ASC" or "DESC"
11158 getSortState : function(){
11159 return this.sortInfo;
11163 applySort : function(){
11164 if(this.sortInfo && !this.remoteSort){
11165 var s = this.sortInfo, f = s.field;
11166 var st = this.fields.get(f).sortType;
11167 var fn = function(r1, r2){
11168 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11169 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11171 this.data.sort(s.direction, fn);
11172 if(this.snapshot && this.snapshot != this.data){
11173 this.snapshot.sort(s.direction, fn);
11179 * Sets the default sort column and order to be used by the next load operation.
11180 * @param {String} fieldName The name of the field to sort by.
11181 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11183 setDefaultSort : function(field, dir){
11184 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11188 * Sort the Records.
11189 * If remote sorting is used, the sort is performed on the server, and the cache is
11190 * reloaded. If local sorting is used, the cache is sorted internally.
11191 * @param {String} fieldName The name of the field to sort by.
11192 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11194 sort : function(fieldName, dir){
11195 var f = this.fields.get(fieldName);
11197 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11199 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11200 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11205 this.sortToggle[f.name] = dir;
11206 this.sortInfo = {field: f.name, direction: dir};
11207 if(!this.remoteSort){
11209 this.fireEvent("datachanged", this);
11211 this.load(this.lastOptions);
11216 * Calls the specified function for each of the Records in the cache.
11217 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11218 * Returning <em>false</em> aborts and exits the iteration.
11219 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11221 each : function(fn, scope){
11222 this.data.each(fn, scope);
11226 * Gets all records modified since the last commit. Modified records are persisted across load operations
11227 * (e.g., during paging).
11228 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11230 getModifiedRecords : function(){
11231 return this.modified;
11235 createFilterFn : function(property, value, anyMatch){
11236 if(!value.exec){ // not a regex
11237 value = String(value);
11238 if(value.length == 0){
11241 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11243 return function(r){
11244 return value.test(r.data[property]);
11249 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11250 * @param {String} property A field on your records
11251 * @param {Number} start The record index to start at (defaults to 0)
11252 * @param {Number} end The last record index to include (defaults to length - 1)
11253 * @return {Number} The sum
11255 sum : function(property, start, end){
11256 var rs = this.data.items, v = 0;
11257 start = start || 0;
11258 end = (end || end === 0) ? end : rs.length-1;
11260 for(var i = start; i <= end; i++){
11261 v += (rs[i].data[property] || 0);
11267 * Filter the records by a specified property.
11268 * @param {String} field A field on your records
11269 * @param {String/RegExp} value Either a string that the field
11270 * should start with or a RegExp to test against the field
11271 * @param {Boolean} anyMatch True to match any part not just the beginning
11273 filter : function(property, value, anyMatch){
11274 var fn = this.createFilterFn(property, value, anyMatch);
11275 return fn ? this.filterBy(fn) : this.clearFilter();
11279 * Filter by a function. The specified function will be called with each
11280 * record in this data source. If the function returns true the record is included,
11281 * otherwise it is filtered.
11282 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11283 * @param {Object} scope (optional) The scope of the function (defaults to this)
11285 filterBy : function(fn, scope){
11286 this.snapshot = this.snapshot || this.data;
11287 this.data = this.queryBy(fn, scope||this);
11288 this.fireEvent("datachanged", this);
11292 * Query the records by a specified property.
11293 * @param {String} field A field on your records
11294 * @param {String/RegExp} value Either a string that the field
11295 * should start with or a RegExp to test against the field
11296 * @param {Boolean} anyMatch True to match any part not just the beginning
11297 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11299 query : function(property, value, anyMatch){
11300 var fn = this.createFilterFn(property, value, anyMatch);
11301 return fn ? this.queryBy(fn) : this.data.clone();
11305 * Query by a function. The specified function will be called with each
11306 * record in this data source. If the function returns true the record is included
11308 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11309 * @param {Object} scope (optional) The scope of the function (defaults to this)
11310 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11312 queryBy : function(fn, scope){
11313 var data = this.snapshot || this.data;
11314 return data.filterBy(fn, scope||this);
11318 * Collects unique values for a particular dataIndex from this store.
11319 * @param {String} dataIndex The property to collect
11320 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11321 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11322 * @return {Array} An array of the unique values
11324 collect : function(dataIndex, allowNull, bypassFilter){
11325 var d = (bypassFilter === true && this.snapshot) ?
11326 this.snapshot.items : this.data.items;
11327 var v, sv, r = [], l = {};
11328 for(var i = 0, len = d.length; i < len; i++){
11329 v = d[i].data[dataIndex];
11331 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11340 * Revert to a view of the Record cache with no filtering applied.
11341 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11343 clearFilter : function(suppressEvent){
11344 if(this.snapshot && this.snapshot != this.data){
11345 this.data = this.snapshot;
11346 delete this.snapshot;
11347 if(suppressEvent !== true){
11348 this.fireEvent("datachanged", this);
11354 afterEdit : function(record){
11355 if(this.modified.indexOf(record) == -1){
11356 this.modified.push(record);
11358 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11362 afterReject : function(record){
11363 this.modified.remove(record);
11364 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11368 afterCommit : function(record){
11369 this.modified.remove(record);
11370 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11374 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11375 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11377 commitChanges : function(){
11378 var m = this.modified.slice(0);
11379 this.modified = [];
11380 for(var i = 0, len = m.length; i < len; i++){
11386 * Cancel outstanding changes on all changed records.
11388 rejectChanges : function(){
11389 var m = this.modified.slice(0);
11390 this.modified = [];
11391 for(var i = 0, len = m.length; i < len; i++){
11396 onMetaChange : function(meta, rtype, o){
11397 this.recordType = rtype;
11398 this.fields = rtype.prototype.fields;
11399 delete this.snapshot;
11400 this.sortInfo = meta.sortInfo || this.sortInfo;
11401 this.modified = [];
11402 this.fireEvent('metachange', this, this.reader.meta);
11405 moveIndex : function(data, type)
11407 var index = this.indexOf(data);
11409 var newIndex = index + type;
11413 this.insert(newIndex, data);
11418 * Ext JS Library 1.1.1
11419 * Copyright(c) 2006-2007, Ext JS, LLC.
11421 * Originally Released Under LGPL - original licence link has changed is not relivant.
11424 * <script type="text/javascript">
11428 * @class Roo.data.SimpleStore
11429 * @extends Roo.data.Store
11430 * Small helper class to make creating Stores from Array data easier.
11431 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11432 * @cfg {Array} fields An array of field definition objects, or field name strings.
11433 * @cfg {Array} data The multi-dimensional array of data
11435 * @param {Object} config
11437 Roo.data.SimpleStore = function(config){
11438 Roo.data.SimpleStore.superclass.constructor.call(this, {
11440 reader: new Roo.data.ArrayReader({
11443 Roo.data.Record.create(config.fields)
11445 proxy : new Roo.data.MemoryProxy(config.data)
11449 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11451 * Ext JS Library 1.1.1
11452 * Copyright(c) 2006-2007, Ext JS, LLC.
11454 * Originally Released Under LGPL - original licence link has changed is not relivant.
11457 * <script type="text/javascript">
11462 * @extends Roo.data.Store
11463 * @class Roo.data.JsonStore
11464 * Small helper class to make creating Stores for JSON data easier. <br/>
11466 var store = new Roo.data.JsonStore({
11467 url: 'get-images.php',
11469 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11472 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11473 * JsonReader and HttpProxy (unless inline data is provided).</b>
11474 * @cfg {Array} fields An array of field definition objects, or field name strings.
11476 * @param {Object} config
11478 Roo.data.JsonStore = function(c){
11479 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11480 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11481 reader: new Roo.data.JsonReader(c, c.fields)
11484 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11486 * Ext JS Library 1.1.1
11487 * Copyright(c) 2006-2007, Ext JS, LLC.
11489 * Originally Released Under LGPL - original licence link has changed is not relivant.
11492 * <script type="text/javascript">
11496 Roo.data.Field = function(config){
11497 if(typeof config == "string"){
11498 config = {name: config};
11500 Roo.apply(this, config);
11503 this.type = "auto";
11506 var st = Roo.data.SortTypes;
11507 // named sortTypes are supported, here we look them up
11508 if(typeof this.sortType == "string"){
11509 this.sortType = st[this.sortType];
11512 // set default sortType for strings and dates
11513 if(!this.sortType){
11516 this.sortType = st.asUCString;
11519 this.sortType = st.asDate;
11522 this.sortType = st.none;
11527 var stripRe = /[\$,%]/g;
11529 // prebuilt conversion function for this field, instead of
11530 // switching every time we're reading a value
11532 var cv, dateFormat = this.dateFormat;
11537 cv = function(v){ return v; };
11540 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11544 return v !== undefined && v !== null && v !== '' ?
11545 parseInt(String(v).replace(stripRe, ""), 10) : '';
11550 return v !== undefined && v !== null && v !== '' ?
11551 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11556 cv = function(v){ return v === true || v === "true" || v == 1; };
11563 if(v instanceof Date){
11567 if(dateFormat == "timestamp"){
11568 return new Date(v*1000);
11570 return Date.parseDate(v, dateFormat);
11572 var parsed = Date.parse(v);
11573 return parsed ? new Date(parsed) : null;
11582 Roo.data.Field.prototype = {
11590 * Ext JS Library 1.1.1
11591 * Copyright(c) 2006-2007, Ext JS, LLC.
11593 * Originally Released Under LGPL - original licence link has changed is not relivant.
11596 * <script type="text/javascript">
11599 // Base class for reading structured data from a data source. This class is intended to be
11600 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11603 * @class Roo.data.DataReader
11604 * Base class for reading structured data from a data source. This class is intended to be
11605 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11608 Roo.data.DataReader = function(meta, recordType){
11612 this.recordType = recordType instanceof Array ?
11613 Roo.data.Record.create(recordType) : recordType;
11616 Roo.data.DataReader.prototype = {
11618 * Create an empty record
11619 * @param {Object} data (optional) - overlay some values
11620 * @return {Roo.data.Record} record created.
11622 newRow : function(d) {
11624 this.recordType.prototype.fields.each(function(c) {
11626 case 'int' : da[c.name] = 0; break;
11627 case 'date' : da[c.name] = new Date(); break;
11628 case 'float' : da[c.name] = 0.0; break;
11629 case 'boolean' : da[c.name] = false; break;
11630 default : da[c.name] = ""; break;
11634 return new this.recordType(Roo.apply(da, d));
11639 * Ext JS Library 1.1.1
11640 * Copyright(c) 2006-2007, Ext JS, LLC.
11642 * Originally Released Under LGPL - original licence link has changed is not relivant.
11645 * <script type="text/javascript">
11649 * @class Roo.data.DataProxy
11650 * @extends Roo.data.Observable
11651 * This class is an abstract base class for implementations which provide retrieval of
11652 * unformatted data objects.<br>
11654 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11655 * (of the appropriate type which knows how to parse the data object) to provide a block of
11656 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11658 * Custom implementations must implement the load method as described in
11659 * {@link Roo.data.HttpProxy#load}.
11661 Roo.data.DataProxy = function(){
11664 * @event beforeload
11665 * Fires before a network request is made to retrieve a data object.
11666 * @param {Object} This DataProxy object.
11667 * @param {Object} params The params parameter to the load function.
11672 * Fires before the load method's callback is called.
11673 * @param {Object} This DataProxy object.
11674 * @param {Object} o The data object.
11675 * @param {Object} arg The callback argument object passed to the load function.
11679 * @event loadexception
11680 * Fires if an Exception occurs during data retrieval.
11681 * @param {Object} This DataProxy object.
11682 * @param {Object} o The data object.
11683 * @param {Object} arg The callback argument object passed to the load function.
11684 * @param {Object} e The Exception.
11686 loadexception : true
11688 Roo.data.DataProxy.superclass.constructor.call(this);
11691 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11694 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11698 * Ext JS Library 1.1.1
11699 * Copyright(c) 2006-2007, Ext JS, LLC.
11701 * Originally Released Under LGPL - original licence link has changed is not relivant.
11704 * <script type="text/javascript">
11707 * @class Roo.data.MemoryProxy
11708 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11709 * to the Reader when its load method is called.
11711 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11713 Roo.data.MemoryProxy = function(data){
11717 Roo.data.MemoryProxy.superclass.constructor.call(this);
11721 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11724 * Load data from the requested source (in this case an in-memory
11725 * data object passed to the constructor), read the data object into
11726 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11727 * process that block using the passed callback.
11728 * @param {Object} params This parameter is not used by the MemoryProxy class.
11729 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11730 * object into a block of Roo.data.Records.
11731 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11732 * The function must be passed <ul>
11733 * <li>The Record block object</li>
11734 * <li>The "arg" argument from the load function</li>
11735 * <li>A boolean success indicator</li>
11737 * @param {Object} scope The scope in which to call the callback
11738 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11740 load : function(params, reader, callback, scope, arg){
11741 params = params || {};
11744 result = reader.readRecords(this.data);
11746 this.fireEvent("loadexception", this, arg, null, e);
11747 callback.call(scope, null, arg, false);
11750 callback.call(scope, result, arg, true);
11754 update : function(params, records){
11759 * Ext JS Library 1.1.1
11760 * Copyright(c) 2006-2007, Ext JS, LLC.
11762 * Originally Released Under LGPL - original licence link has changed is not relivant.
11765 * <script type="text/javascript">
11768 * @class Roo.data.HttpProxy
11769 * @extends Roo.data.DataProxy
11770 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11771 * configured to reference a certain URL.<br><br>
11773 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11774 * from which the running page was served.<br><br>
11776 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11778 * Be aware that to enable the browser to parse an XML document, the server must set
11779 * the Content-Type header in the HTTP response to "text/xml".
11781 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11782 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11783 * will be used to make the request.
11785 Roo.data.HttpProxy = function(conn){
11786 Roo.data.HttpProxy.superclass.constructor.call(this);
11787 // is conn a conn config or a real conn?
11789 this.useAjax = !conn || !conn.events;
11793 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11794 // thse are take from connection...
11797 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11800 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11801 * extra parameters to each request made by this object. (defaults to undefined)
11804 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11805 * to each request made by this object. (defaults to undefined)
11808 * @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)
11811 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11814 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11820 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11824 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11825 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11826 * a finer-grained basis than the DataProxy events.
11828 getConnection : function(){
11829 return this.useAjax ? Roo.Ajax : this.conn;
11833 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11834 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11835 * process that block using the passed callback.
11836 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11837 * for the request to the remote server.
11838 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11839 * object into a block of Roo.data.Records.
11840 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11841 * The function must be passed <ul>
11842 * <li>The Record block object</li>
11843 * <li>The "arg" argument from the load function</li>
11844 * <li>A boolean success indicator</li>
11846 * @param {Object} scope The scope in which to call the callback
11847 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11849 load : function(params, reader, callback, scope, arg){
11850 if(this.fireEvent("beforeload", this, params) !== false){
11852 params : params || {},
11854 callback : callback,
11859 callback : this.loadResponse,
11863 Roo.applyIf(o, this.conn);
11864 if(this.activeRequest){
11865 Roo.Ajax.abort(this.activeRequest);
11867 this.activeRequest = Roo.Ajax.request(o);
11869 this.conn.request(o);
11872 callback.call(scope||this, null, arg, false);
11877 loadResponse : function(o, success, response){
11878 delete this.activeRequest;
11880 this.fireEvent("loadexception", this, o, response);
11881 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11886 result = o.reader.read(response);
11888 this.fireEvent("loadexception", this, o, response, e);
11889 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11893 this.fireEvent("load", this, o, o.request.arg);
11894 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11898 update : function(dataSet){
11903 updateResponse : function(dataSet){
11908 * Ext JS Library 1.1.1
11909 * Copyright(c) 2006-2007, Ext JS, LLC.
11911 * Originally Released Under LGPL - original licence link has changed is not relivant.
11914 * <script type="text/javascript">
11918 * @class Roo.data.ScriptTagProxy
11919 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11920 * other than the originating domain of the running page.<br><br>
11922 * <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
11923 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11925 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11926 * source code that is used as the source inside a <script> tag.<br><br>
11928 * In order for the browser to process the returned data, the server must wrap the data object
11929 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11930 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11931 * depending on whether the callback name was passed:
11934 boolean scriptTag = false;
11935 String cb = request.getParameter("callback");
11938 response.setContentType("text/javascript");
11940 response.setContentType("application/x-json");
11942 Writer out = response.getWriter();
11944 out.write(cb + "(");
11946 out.print(dataBlock.toJsonString());
11953 * @param {Object} config A configuration object.
11955 Roo.data.ScriptTagProxy = function(config){
11956 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11957 Roo.apply(this, config);
11958 this.head = document.getElementsByTagName("head")[0];
11961 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11963 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11965 * @cfg {String} url The URL from which to request the data object.
11968 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11972 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11973 * the server the name of the callback function set up by the load call to process the returned data object.
11974 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11975 * javascript output which calls this named function passing the data object as its only parameter.
11977 callbackParam : "callback",
11979 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11980 * name to the request.
11985 * Load data from the configured URL, read the data object into
11986 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11987 * process that block using the passed callback.
11988 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11989 * for the request to the remote server.
11990 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11991 * object into a block of Roo.data.Records.
11992 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11993 * The function must be passed <ul>
11994 * <li>The Record block object</li>
11995 * <li>The "arg" argument from the load function</li>
11996 * <li>A boolean success indicator</li>
11998 * @param {Object} scope The scope in which to call the callback
11999 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12001 load : function(params, reader, callback, scope, arg){
12002 if(this.fireEvent("beforeload", this, params) !== false){
12004 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12006 var url = this.url;
12007 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12009 url += "&_dc=" + (new Date().getTime());
12011 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12014 cb : "stcCallback"+transId,
12015 scriptId : "stcScript"+transId,
12019 callback : callback,
12025 window[trans.cb] = function(o){
12026 conn.handleResponse(o, trans);
12029 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12031 if(this.autoAbort !== false){
12035 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12037 var script = document.createElement("script");
12038 script.setAttribute("src", url);
12039 script.setAttribute("type", "text/javascript");
12040 script.setAttribute("id", trans.scriptId);
12041 this.head.appendChild(script);
12043 this.trans = trans;
12045 callback.call(scope||this, null, arg, false);
12050 isLoading : function(){
12051 return this.trans ? true : false;
12055 * Abort the current server request.
12057 abort : function(){
12058 if(this.isLoading()){
12059 this.destroyTrans(this.trans);
12064 destroyTrans : function(trans, isLoaded){
12065 this.head.removeChild(document.getElementById(trans.scriptId));
12066 clearTimeout(trans.timeoutId);
12068 window[trans.cb] = undefined;
12070 delete window[trans.cb];
12073 // if hasn't been loaded, wait for load to remove it to prevent script error
12074 window[trans.cb] = function(){
12075 window[trans.cb] = undefined;
12077 delete window[trans.cb];
12084 handleResponse : function(o, trans){
12085 this.trans = false;
12086 this.destroyTrans(trans, true);
12089 result = trans.reader.readRecords(o);
12091 this.fireEvent("loadexception", this, o, trans.arg, e);
12092 trans.callback.call(trans.scope||window, null, trans.arg, false);
12095 this.fireEvent("load", this, o, trans.arg);
12096 trans.callback.call(trans.scope||window, result, trans.arg, true);
12100 handleFailure : function(trans){
12101 this.trans = false;
12102 this.destroyTrans(trans, false);
12103 this.fireEvent("loadexception", this, null, trans.arg);
12104 trans.callback.call(trans.scope||window, null, trans.arg, false);
12108 * Ext JS Library 1.1.1
12109 * Copyright(c) 2006-2007, Ext JS, LLC.
12111 * Originally Released Under LGPL - original licence link has changed is not relivant.
12114 * <script type="text/javascript">
12118 * @class Roo.data.JsonReader
12119 * @extends Roo.data.DataReader
12120 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12121 * based on mappings in a provided Roo.data.Record constructor.
12123 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12124 * in the reply previously.
12129 var RecordDef = Roo.data.Record.create([
12130 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12131 {name: 'occupation'} // This field will use "occupation" as the mapping.
12133 var myReader = new Roo.data.JsonReader({
12134 totalProperty: "results", // The property which contains the total dataset size (optional)
12135 root: "rows", // The property which contains an Array of row objects
12136 id: "id" // The property within each row object that provides an ID for the record (optional)
12140 * This would consume a JSON file like this:
12142 { 'results': 2, 'rows': [
12143 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12144 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12147 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12148 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12149 * paged from the remote server.
12150 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12151 * @cfg {String} root name of the property which contains the Array of row objects.
12152 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12153 * @cfg {Array} fields Array of field definition objects
12155 * Create a new JsonReader
12156 * @param {Object} meta Metadata configuration options
12157 * @param {Object} recordType Either an Array of field definition objects,
12158 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12160 Roo.data.JsonReader = function(meta, recordType){
12163 // set some defaults:
12164 Roo.applyIf(meta, {
12165 totalProperty: 'total',
12166 successProperty : 'success',
12171 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12173 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12176 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12177 * Used by Store query builder to append _requestMeta to params.
12180 metaFromRemote : false,
12182 * This method is only used by a DataProxy which has retrieved data from a remote server.
12183 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12184 * @return {Object} data A data block which is used by an Roo.data.Store object as
12185 * a cache of Roo.data.Records.
12187 read : function(response){
12188 var json = response.responseText;
12190 var o = /* eval:var:o */ eval("("+json+")");
12192 throw {message: "JsonReader.read: Json object not found"};
12198 this.metaFromRemote = true;
12199 this.meta = o.metaData;
12200 this.recordType = Roo.data.Record.create(o.metaData.fields);
12201 this.onMetaChange(this.meta, this.recordType, o);
12203 return this.readRecords(o);
12206 // private function a store will implement
12207 onMetaChange : function(meta, recordType, o){
12214 simpleAccess: function(obj, subsc) {
12221 getJsonAccessor: function(){
12223 return function(expr) {
12225 return(re.test(expr))
12226 ? new Function("obj", "return obj." + expr)
12231 return Roo.emptyFn;
12236 * Create a data block containing Roo.data.Records from an XML document.
12237 * @param {Object} o An object which contains an Array of row objects in the property specified
12238 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12239 * which contains the total size of the dataset.
12240 * @return {Object} data A data block which is used by an Roo.data.Store object as
12241 * a cache of Roo.data.Records.
12243 readRecords : function(o){
12245 * After any data loads, the raw JSON data is available for further custom processing.
12249 var s = this.meta, Record = this.recordType,
12250 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12252 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12254 if(s.totalProperty) {
12255 this.getTotal = this.getJsonAccessor(s.totalProperty);
12257 if(s.successProperty) {
12258 this.getSuccess = this.getJsonAccessor(s.successProperty);
12260 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12262 var g = this.getJsonAccessor(s.id);
12263 this.getId = function(rec) {
12265 return (r === undefined || r === "") ? null : r;
12268 this.getId = function(){return null;};
12271 for(var jj = 0; jj < fl; jj++){
12273 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12274 this.ef[jj] = this.getJsonAccessor(map);
12278 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12279 if(s.totalProperty){
12280 var vt = parseInt(this.getTotal(o), 10);
12285 if(s.successProperty){
12286 var vs = this.getSuccess(o);
12287 if(vs === false || vs === 'false'){
12292 for(var i = 0; i < c; i++){
12295 var id = this.getId(n);
12296 for(var j = 0; j < fl; j++){
12298 var v = this.ef[j](n);
12300 Roo.log('missing convert for ' + f.name);
12304 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12306 var record = new Record(values, id);
12308 records[i] = record;
12314 totalRecords : totalRecords
12319 * Ext JS Library 1.1.1
12320 * Copyright(c) 2006-2007, Ext JS, LLC.
12322 * Originally Released Under LGPL - original licence link has changed is not relivant.
12325 * <script type="text/javascript">
12329 * @class Roo.data.ArrayReader
12330 * @extends Roo.data.DataReader
12331 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12332 * Each element of that Array represents a row of data fields. The
12333 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12334 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12338 var RecordDef = Roo.data.Record.create([
12339 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12340 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12342 var myReader = new Roo.data.ArrayReader({
12343 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12347 * This would consume an Array like this:
12349 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12351 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12353 * Create a new JsonReader
12354 * @param {Object} meta Metadata configuration options.
12355 * @param {Object} recordType Either an Array of field definition objects
12356 * as specified to {@link Roo.data.Record#create},
12357 * or an {@link Roo.data.Record} object
12358 * created using {@link Roo.data.Record#create}.
12360 Roo.data.ArrayReader = function(meta, recordType){
12361 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12364 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12366 * Create a data block containing Roo.data.Records from an XML document.
12367 * @param {Object} o An Array of row objects which represents the dataset.
12368 * @return {Object} data A data block which is used by an Roo.data.Store object as
12369 * a cache of Roo.data.Records.
12371 readRecords : function(o){
12372 var sid = this.meta ? this.meta.id : null;
12373 var recordType = this.recordType, fields = recordType.prototype.fields;
12376 for(var i = 0; i < root.length; i++){
12379 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12380 for(var j = 0, jlen = fields.length; j < jlen; j++){
12381 var f = fields.items[j];
12382 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12383 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12385 values[f.name] = v;
12387 var record = new recordType(values, id);
12389 records[records.length] = record;
12393 totalRecords : records.length
12402 * @class Roo.bootstrap.ComboBox
12403 * @extends Roo.bootstrap.TriggerField
12404 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12405 * @cfg {Boolean} append (true|false) default false
12406 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12407 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12408 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12409 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12410 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12411 * @cfg {Boolean} animate default true
12412 * @cfg {Boolean} emptyResultText only for touch device
12413 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12414 * @cfg {String} emptyTitle default ''
12416 * Create a new ComboBox.
12417 * @param {Object} config Configuration options
12419 Roo.bootstrap.ComboBox = function(config){
12420 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12424 * Fires when the dropdown list is expanded
12425 * @param {Roo.bootstrap.ComboBox} combo This combo box
12430 * Fires when the dropdown list is collapsed
12431 * @param {Roo.bootstrap.ComboBox} combo This combo box
12435 * @event beforeselect
12436 * Fires before a list item is selected. Return false to cancel the selection.
12437 * @param {Roo.bootstrap.ComboBox} combo This combo box
12438 * @param {Roo.data.Record} record The data record returned from the underlying store
12439 * @param {Number} index The index of the selected item in the dropdown list
12441 'beforeselect' : true,
12444 * Fires when a list item is selected
12445 * @param {Roo.bootstrap.ComboBox} combo This combo box
12446 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12447 * @param {Number} index The index of the selected item in the dropdown list
12451 * @event beforequery
12452 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12453 * The event object passed has these properties:
12454 * @param {Roo.bootstrap.ComboBox} combo This combo box
12455 * @param {String} query The query
12456 * @param {Boolean} forceAll true to force "all" query
12457 * @param {Boolean} cancel true to cancel the query
12458 * @param {Object} e The query event object
12460 'beforequery': true,
12463 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12464 * @param {Roo.bootstrap.ComboBox} combo This combo box
12469 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12470 * @param {Roo.bootstrap.ComboBox} combo This combo box
12471 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12476 * Fires when the remove value from the combobox array
12477 * @param {Roo.bootstrap.ComboBox} combo This combo box
12481 * @event afterremove
12482 * Fires when the remove value from the combobox array
12483 * @param {Roo.bootstrap.ComboBox} combo This combo box
12485 'afterremove' : true,
12487 * @event specialfilter
12488 * Fires when specialfilter
12489 * @param {Roo.bootstrap.ComboBox} combo This combo box
12491 'specialfilter' : true,
12494 * Fires when tick the element
12495 * @param {Roo.bootstrap.ComboBox} combo This combo box
12499 * @event touchviewdisplay
12500 * Fires when touch view require special display (default is using displayField)
12501 * @param {Roo.bootstrap.ComboBox} combo This combo box
12502 * @param {Object} cfg set html .
12504 'touchviewdisplay' : true
12509 this.tickItems = [];
12511 this.selectedIndex = -1;
12512 if(this.mode == 'local'){
12513 if(config.queryDelay === undefined){
12514 this.queryDelay = 10;
12516 if(config.minChars === undefined){
12522 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12525 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12526 * rendering into an Roo.Editor, defaults to false)
12529 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12530 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12533 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12536 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12537 * the dropdown list (defaults to undefined, with no header element)
12541 * @cfg {String/Roo.Template} tpl The template to use to render the output
12545 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12547 listWidth: undefined,
12549 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12550 * mode = 'remote' or 'text' if mode = 'local')
12552 displayField: undefined,
12555 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12556 * mode = 'remote' or 'value' if mode = 'local').
12557 * Note: use of a valueField requires the user make a selection
12558 * in order for a value to be mapped.
12560 valueField: undefined,
12562 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12567 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12568 * field's data value (defaults to the underlying DOM element's name)
12570 hiddenName: undefined,
12572 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12576 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12578 selectedClass: 'active',
12581 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12585 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12586 * anchor positions (defaults to 'tl-bl')
12588 listAlign: 'tl-bl?',
12590 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12594 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12595 * query specified by the allQuery config option (defaults to 'query')
12597 triggerAction: 'query',
12599 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12600 * (defaults to 4, does not apply if editable = false)
12604 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12605 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12609 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12610 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12614 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12615 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12619 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12620 * when editable = true (defaults to false)
12622 selectOnFocus:false,
12624 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12626 queryParam: 'query',
12628 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12629 * when mode = 'remote' (defaults to 'Loading...')
12631 loadingText: 'Loading...',
12633 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12637 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12641 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12642 * traditional select (defaults to true)
12646 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12650 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12654 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12655 * listWidth has a higher value)
12659 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12660 * allow the user to set arbitrary text into the field (defaults to false)
12662 forceSelection:false,
12664 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12665 * if typeAhead = true (defaults to 250)
12667 typeAheadDelay : 250,
12669 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12670 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12672 valueNotFoundText : undefined,
12674 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12676 blockFocus : false,
12679 * @cfg {Boolean} disableClear Disable showing of clear button.
12681 disableClear : false,
12683 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12685 alwaysQuery : false,
12688 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12693 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12695 invalidClass : "has-warning",
12698 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12700 validClass : "has-success",
12703 * @cfg {Boolean} specialFilter (true|false) special filter default false
12705 specialFilter : false,
12708 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12710 mobileTouchView : true,
12713 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12715 useNativeIOS : false,
12717 ios_options : false,
12729 btnPosition : 'right',
12730 triggerList : true,
12731 showToggleBtn : true,
12733 emptyResultText: 'Empty',
12734 triggerText : 'Select',
12737 // element that contains real text value.. (when hidden is used..)
12739 getAutoCreate : function()
12744 * Render classic select for iso
12747 if(Roo.isIOS && this.useNativeIOS){
12748 cfg = this.getAutoCreateNativeIOS();
12756 if(Roo.isTouch && this.mobileTouchView){
12757 cfg = this.getAutoCreateTouchView();
12764 if(!this.tickable){
12765 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12770 * ComboBox with tickable selections
12773 var align = this.labelAlign || this.parentLabelAlign();
12776 cls : 'form-group roo-combobox-tickable' //input-group
12779 var btn_text_select = '';
12780 var btn_text_done = '';
12781 var btn_text_cancel = '';
12783 if (this.btn_text_show) {
12784 btn_text_select = 'Select';
12785 btn_text_done = 'Done';
12786 btn_text_cancel = 'Cancel';
12791 cls : 'tickable-buttons',
12796 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12797 //html : this.triggerText
12798 html: btn_text_select
12804 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12806 html: btn_text_done
12812 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12814 html: btn_text_cancel
12820 buttons.cn.unshift({
12822 cls: 'roo-select2-search-field-input'
12828 Roo.each(buttons.cn, function(c){
12830 c.cls += ' btn-' + _this.size;
12833 if (_this.disabled) {
12844 cls: 'form-hidden-field'
12848 cls: 'roo-select2-choices',
12852 cls: 'roo-select2-search-field',
12863 cls: 'roo-select2-container input-group roo-select2-container-multi',
12868 // cls: 'typeahead typeahead-long dropdown-menu',
12869 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12874 if(this.hasFeedback && !this.allowBlank){
12878 cls: 'glyphicon form-control-feedback'
12881 combobox.cn.push(feedback);
12885 if (align ==='left' && this.fieldLabel.length) {
12887 cfg.cls += ' roo-form-group-label-left';
12892 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12893 tooltip : 'This field is required'
12898 cls : 'control-label',
12899 html : this.fieldLabel
12911 var labelCfg = cfg.cn[1];
12912 var contentCfg = cfg.cn[2];
12915 if(this.indicatorpos == 'right'){
12921 cls : 'control-label',
12925 html : this.fieldLabel
12929 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12930 tooltip : 'This field is required'
12945 labelCfg = cfg.cn[0];
12946 contentCfg = cfg.cn[1];
12950 if(this.labelWidth > 12){
12951 labelCfg.style = "width: " + this.labelWidth + 'px';
12954 if(this.labelWidth < 13 && this.labelmd == 0){
12955 this.labelmd = this.labelWidth;
12958 if(this.labellg > 0){
12959 labelCfg.cls += ' col-lg-' + this.labellg;
12960 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12963 if(this.labelmd > 0){
12964 labelCfg.cls += ' col-md-' + this.labelmd;
12965 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12968 if(this.labelsm > 0){
12969 labelCfg.cls += ' col-sm-' + this.labelsm;
12970 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12973 if(this.labelxs > 0){
12974 labelCfg.cls += ' col-xs-' + this.labelxs;
12975 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12979 } else if ( this.fieldLabel.length) {
12980 // Roo.log(" label");
12984 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12985 tooltip : 'This field is required'
12989 //cls : 'input-group-addon',
12990 html : this.fieldLabel
12995 if(this.indicatorpos == 'right'){
12999 //cls : 'input-group-addon',
13000 html : this.fieldLabel
13004 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13005 tooltip : 'This field is required'
13014 // Roo.log(" no label && no align");
13021 ['xs','sm','md','lg'].map(function(size){
13022 if (settings[size]) {
13023 cfg.cls += ' col-' + size + '-' + settings[size];
13031 _initEventsCalled : false,
13034 initEvents: function()
13036 if (this._initEventsCalled) { // as we call render... prevent looping...
13039 this._initEventsCalled = true;
13042 throw "can not find store for combo";
13045 this.indicator = this.indicatorEl();
13047 this.store = Roo.factory(this.store, Roo.data);
13048 this.store.parent = this;
13050 // if we are building from html. then this element is so complex, that we can not really
13051 // use the rendered HTML.
13052 // so we have to trash and replace the previous code.
13053 if (Roo.XComponent.build_from_html) {
13054 // remove this element....
13055 var e = this.el.dom, k=0;
13056 while (e ) { e = e.previousSibling; ++k;}
13061 this.rendered = false;
13063 this.render(this.parent().getChildContainer(true), k);
13066 if(Roo.isIOS && this.useNativeIOS){
13067 this.initIOSView();
13075 if(Roo.isTouch && this.mobileTouchView){
13076 this.initTouchView();
13081 this.initTickableEvents();
13085 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13087 if(this.hiddenName){
13089 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13091 this.hiddenField.dom.value =
13092 this.hiddenValue !== undefined ? this.hiddenValue :
13093 this.value !== undefined ? this.value : '';
13095 // prevent input submission
13096 this.el.dom.removeAttribute('name');
13097 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13102 // this.el.dom.setAttribute('autocomplete', 'off');
13105 var cls = 'x-combo-list';
13107 //this.list = new Roo.Layer({
13108 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13114 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13115 _this.list.setWidth(lw);
13118 this.list.on('mouseover', this.onViewOver, this);
13119 this.list.on('mousemove', this.onViewMove, this);
13120 this.list.on('scroll', this.onViewScroll, this);
13123 this.list.swallowEvent('mousewheel');
13124 this.assetHeight = 0;
13127 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13128 this.assetHeight += this.header.getHeight();
13131 this.innerList = this.list.createChild({cls:cls+'-inner'});
13132 this.innerList.on('mouseover', this.onViewOver, this);
13133 this.innerList.on('mousemove', this.onViewMove, this);
13134 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13136 if(this.allowBlank && !this.pageSize && !this.disableClear){
13137 this.footer = this.list.createChild({cls:cls+'-ft'});
13138 this.pageTb = new Roo.Toolbar(this.footer);
13142 this.footer = this.list.createChild({cls:cls+'-ft'});
13143 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13144 {pageSize: this.pageSize});
13148 if (this.pageTb && this.allowBlank && !this.disableClear) {
13150 this.pageTb.add(new Roo.Toolbar.Fill(), {
13151 cls: 'x-btn-icon x-btn-clear',
13153 handler: function()
13156 _this.clearValue();
13157 _this.onSelect(false, -1);
13162 this.assetHeight += this.footer.getHeight();
13167 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13170 this.view = new Roo.View(this.list, this.tpl, {
13171 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13173 //this.view.wrapEl.setDisplayed(false);
13174 this.view.on('click', this.onViewClick, this);
13177 this.store.on('beforeload', this.onBeforeLoad, this);
13178 this.store.on('load', this.onLoad, this);
13179 this.store.on('loadexception', this.onLoadException, this);
13181 if(this.resizable){
13182 this.resizer = new Roo.Resizable(this.list, {
13183 pinned:true, handles:'se'
13185 this.resizer.on('resize', function(r, w, h){
13186 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13187 this.listWidth = w;
13188 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13189 this.restrictHeight();
13191 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13194 if(!this.editable){
13195 this.editable = true;
13196 this.setEditable(false);
13201 if (typeof(this.events.add.listeners) != 'undefined') {
13203 this.addicon = this.wrap.createChild(
13204 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13206 this.addicon.on('click', function(e) {
13207 this.fireEvent('add', this);
13210 if (typeof(this.events.edit.listeners) != 'undefined') {
13212 this.editicon = this.wrap.createChild(
13213 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13214 if (this.addicon) {
13215 this.editicon.setStyle('margin-left', '40px');
13217 this.editicon.on('click', function(e) {
13219 // we fire even if inothing is selected..
13220 this.fireEvent('edit', this, this.lastData );
13226 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13227 "up" : function(e){
13228 this.inKeyMode = true;
13232 "down" : function(e){
13233 if(!this.isExpanded()){
13234 this.onTriggerClick();
13236 this.inKeyMode = true;
13241 "enter" : function(e){
13242 // this.onViewClick();
13246 if(this.fireEvent("specialkey", this, e)){
13247 this.onViewClick(false);
13253 "esc" : function(e){
13257 "tab" : function(e){
13260 if(this.fireEvent("specialkey", this, e)){
13261 this.onViewClick(false);
13269 doRelay : function(foo, bar, hname){
13270 if(hname == 'down' || this.scope.isExpanded()){
13271 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13280 this.queryDelay = Math.max(this.queryDelay || 10,
13281 this.mode == 'local' ? 10 : 250);
13284 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13286 if(this.typeAhead){
13287 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13289 if(this.editable !== false){
13290 this.inputEl().on("keyup", this.onKeyUp, this);
13292 if(this.forceSelection){
13293 this.inputEl().on('blur', this.doForce, this);
13297 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13298 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13302 initTickableEvents: function()
13306 if(this.hiddenName){
13308 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13310 this.hiddenField.dom.value =
13311 this.hiddenValue !== undefined ? this.hiddenValue :
13312 this.value !== undefined ? this.value : '';
13314 // prevent input submission
13315 this.el.dom.removeAttribute('name');
13316 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13321 // this.list = this.el.select('ul.dropdown-menu',true).first();
13323 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13324 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13325 if(this.triggerList){
13326 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13329 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13330 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13332 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13333 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13335 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13336 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13338 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13339 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13340 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13343 this.cancelBtn.hide();
13348 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13349 _this.list.setWidth(lw);
13352 this.list.on('mouseover', this.onViewOver, this);
13353 this.list.on('mousemove', this.onViewMove, this);
13355 this.list.on('scroll', this.onViewScroll, this);
13358 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>';
13361 this.view = new Roo.View(this.list, this.tpl, {
13362 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13365 //this.view.wrapEl.setDisplayed(false);
13366 this.view.on('click', this.onViewClick, this);
13370 this.store.on('beforeload', this.onBeforeLoad, this);
13371 this.store.on('load', this.onLoad, this);
13372 this.store.on('loadexception', this.onLoadException, this);
13375 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13376 "up" : function(e){
13377 this.inKeyMode = true;
13381 "down" : function(e){
13382 this.inKeyMode = true;
13386 "enter" : function(e){
13387 if(this.fireEvent("specialkey", this, e)){
13388 this.onViewClick(false);
13394 "esc" : function(e){
13395 this.onTickableFooterButtonClick(e, false, false);
13398 "tab" : function(e){
13399 this.fireEvent("specialkey", this, e);
13401 this.onTickableFooterButtonClick(e, false, false);
13408 doRelay : function(e, fn, key){
13409 if(this.scope.isExpanded()){
13410 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13419 this.queryDelay = Math.max(this.queryDelay || 10,
13420 this.mode == 'local' ? 10 : 250);
13423 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13425 if(this.typeAhead){
13426 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13429 if(this.editable !== false){
13430 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13433 this.indicator = this.indicatorEl();
13435 if(this.indicator){
13436 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13437 this.indicator.hide();
13442 onDestroy : function(){
13444 this.view.setStore(null);
13445 this.view.el.removeAllListeners();
13446 this.view.el.remove();
13447 this.view.purgeListeners();
13450 this.list.dom.innerHTML = '';
13454 this.store.un('beforeload', this.onBeforeLoad, this);
13455 this.store.un('load', this.onLoad, this);
13456 this.store.un('loadexception', this.onLoadException, this);
13458 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13462 fireKey : function(e){
13463 if(e.isNavKeyPress() && !this.list.isVisible()){
13464 this.fireEvent("specialkey", this, e);
13469 onResize: function(w, h){
13470 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13472 // if(typeof w != 'number'){
13473 // // we do not handle it!?!?
13476 // var tw = this.trigger.getWidth();
13477 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13478 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13480 // this.inputEl().setWidth( this.adjustWidth('input', x));
13482 // //this.trigger.setStyle('left', x+'px');
13484 // if(this.list && this.listWidth === undefined){
13485 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13486 // this.list.setWidth(lw);
13487 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13495 * Allow or prevent the user from directly editing the field text. If false is passed,
13496 * the user will only be able to select from the items defined in the dropdown list. This method
13497 * is the runtime equivalent of setting the 'editable' config option at config time.
13498 * @param {Boolean} value True to allow the user to directly edit the field text
13500 setEditable : function(value){
13501 if(value == this.editable){
13504 this.editable = value;
13506 this.inputEl().dom.setAttribute('readOnly', true);
13507 this.inputEl().on('mousedown', this.onTriggerClick, this);
13508 this.inputEl().addClass('x-combo-noedit');
13510 this.inputEl().dom.setAttribute('readOnly', false);
13511 this.inputEl().un('mousedown', this.onTriggerClick, this);
13512 this.inputEl().removeClass('x-combo-noedit');
13518 onBeforeLoad : function(combo,opts){
13519 if(!this.hasFocus){
13523 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13525 this.restrictHeight();
13526 this.selectedIndex = -1;
13530 onLoad : function(){
13532 this.hasQuery = false;
13534 if(!this.hasFocus){
13538 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13539 this.loading.hide();
13542 if(this.store.getCount() > 0){
13545 this.restrictHeight();
13546 if(this.lastQuery == this.allQuery){
13547 if(this.editable && !this.tickable){
13548 this.inputEl().dom.select();
13552 !this.selectByValue(this.value, true) &&
13555 !this.store.lastOptions ||
13556 typeof(this.store.lastOptions.add) == 'undefined' ||
13557 this.store.lastOptions.add != true
13560 this.select(0, true);
13563 if(this.autoFocus){
13566 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13567 this.taTask.delay(this.typeAheadDelay);
13571 this.onEmptyResults();
13577 onLoadException : function()
13579 this.hasQuery = false;
13581 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13582 this.loading.hide();
13585 if(this.tickable && this.editable){
13590 // only causes errors at present
13591 //Roo.log(this.store.reader.jsonData);
13592 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13594 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13600 onTypeAhead : function(){
13601 if(this.store.getCount() > 0){
13602 var r = this.store.getAt(0);
13603 var newValue = r.data[this.displayField];
13604 var len = newValue.length;
13605 var selStart = this.getRawValue().length;
13607 if(selStart != len){
13608 this.setRawValue(newValue);
13609 this.selectText(selStart, newValue.length);
13615 onSelect : function(record, index){
13617 if(this.fireEvent('beforeselect', this, record, index) !== false){
13619 this.setFromData(index > -1 ? record.data : false);
13622 this.fireEvent('select', this, record, index);
13627 * Returns the currently selected field value or empty string if no value is set.
13628 * @return {String} value The selected value
13630 getValue : function()
13632 if(Roo.isIOS && this.useNativeIOS){
13633 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13637 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13640 if(this.valueField){
13641 return typeof this.value != 'undefined' ? this.value : '';
13643 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13647 getRawValue : function()
13649 if(Roo.isIOS && this.useNativeIOS){
13650 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13653 var v = this.inputEl().getValue();
13659 * Clears any text/value currently set in the field
13661 clearValue : function(){
13663 if(this.hiddenField){
13664 this.hiddenField.dom.value = '';
13667 this.setRawValue('');
13668 this.lastSelectionText = '';
13669 this.lastData = false;
13671 var close = this.closeTriggerEl();
13682 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13683 * will be displayed in the field. If the value does not match the data value of an existing item,
13684 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13685 * Otherwise the field will be blank (although the value will still be set).
13686 * @param {String} value The value to match
13688 setValue : function(v)
13690 if(Roo.isIOS && this.useNativeIOS){
13691 this.setIOSValue(v);
13701 if(this.valueField){
13702 var r = this.findRecord(this.valueField, v);
13704 text = r.data[this.displayField];
13705 }else if(this.valueNotFoundText !== undefined){
13706 text = this.valueNotFoundText;
13709 this.lastSelectionText = text;
13710 if(this.hiddenField){
13711 this.hiddenField.dom.value = v;
13713 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13716 var close = this.closeTriggerEl();
13719 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13725 * @property {Object} the last set data for the element
13730 * Sets the value of the field based on a object which is related to the record format for the store.
13731 * @param {Object} value the value to set as. or false on reset?
13733 setFromData : function(o){
13740 var dv = ''; // display value
13741 var vv = ''; // value value..
13743 if (this.displayField) {
13744 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13746 // this is an error condition!!!
13747 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13750 if(this.valueField){
13751 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13754 var close = this.closeTriggerEl();
13757 if(dv.length || vv * 1 > 0){
13759 this.blockFocus=true;
13765 if(this.hiddenField){
13766 this.hiddenField.dom.value = vv;
13768 this.lastSelectionText = dv;
13769 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13773 // no hidden field.. - we store the value in 'value', but still display
13774 // display field!!!!
13775 this.lastSelectionText = dv;
13776 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13783 reset : function(){
13784 // overridden so that last data is reset..
13791 this.setValue(this.originalValue);
13792 //this.clearInvalid();
13793 this.lastData = false;
13795 this.view.clearSelections();
13801 findRecord : function(prop, value){
13803 if(this.store.getCount() > 0){
13804 this.store.each(function(r){
13805 if(r.data[prop] == value){
13815 getName: function()
13817 // returns hidden if it's set..
13818 if (!this.rendered) {return ''};
13819 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13823 onViewMove : function(e, t){
13824 this.inKeyMode = false;
13828 onViewOver : function(e, t){
13829 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13832 var item = this.view.findItemFromChild(t);
13835 var index = this.view.indexOf(item);
13836 this.select(index, false);
13841 onViewClick : function(view, doFocus, el, e)
13843 var index = this.view.getSelectedIndexes()[0];
13845 var r = this.store.getAt(index);
13849 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13856 Roo.each(this.tickItems, function(v,k){
13858 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13860 _this.tickItems.splice(k, 1);
13862 if(typeof(e) == 'undefined' && view == false){
13863 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13875 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13876 this.tickItems.push(r.data);
13879 if(typeof(e) == 'undefined' && view == false){
13880 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13887 this.onSelect(r, index);
13889 if(doFocus !== false && !this.blockFocus){
13890 this.inputEl().focus();
13895 restrictHeight : function(){
13896 //this.innerList.dom.style.height = '';
13897 //var inner = this.innerList.dom;
13898 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13899 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13900 //this.list.beginUpdate();
13901 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13902 this.list.alignTo(this.inputEl(), this.listAlign);
13903 this.list.alignTo(this.inputEl(), this.listAlign);
13904 //this.list.endUpdate();
13908 onEmptyResults : function(){
13910 if(this.tickable && this.editable){
13911 this.restrictHeight();
13919 * Returns true if the dropdown list is expanded, else false.
13921 isExpanded : function(){
13922 return this.list.isVisible();
13926 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13927 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13928 * @param {String} value The data value of the item to select
13929 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13930 * selected item if it is not currently in view (defaults to true)
13931 * @return {Boolean} True if the value matched an item in the list, else false
13933 selectByValue : function(v, scrollIntoView){
13934 if(v !== undefined && v !== null){
13935 var r = this.findRecord(this.valueField || this.displayField, v);
13937 this.select(this.store.indexOf(r), scrollIntoView);
13945 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13946 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13947 * @param {Number} index The zero-based index of the list item to select
13948 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13949 * selected item if it is not currently in view (defaults to true)
13951 select : function(index, scrollIntoView){
13952 this.selectedIndex = index;
13953 this.view.select(index);
13954 if(scrollIntoView !== false){
13955 var el = this.view.getNode(index);
13957 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13960 this.list.scrollChildIntoView(el, false);
13966 selectNext : function(){
13967 var ct = this.store.getCount();
13969 if(this.selectedIndex == -1){
13971 }else if(this.selectedIndex < ct-1){
13972 this.select(this.selectedIndex+1);
13978 selectPrev : function(){
13979 var ct = this.store.getCount();
13981 if(this.selectedIndex == -1){
13983 }else if(this.selectedIndex != 0){
13984 this.select(this.selectedIndex-1);
13990 onKeyUp : function(e){
13991 if(this.editable !== false && !e.isSpecialKey()){
13992 this.lastKey = e.getKey();
13993 this.dqTask.delay(this.queryDelay);
13998 validateBlur : function(){
13999 return !this.list || !this.list.isVisible();
14003 initQuery : function(){
14005 var v = this.getRawValue();
14007 if(this.tickable && this.editable){
14008 v = this.tickableInputEl().getValue();
14015 doForce : function(){
14016 if(this.inputEl().dom.value.length > 0){
14017 this.inputEl().dom.value =
14018 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14024 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14025 * query allowing the query action to be canceled if needed.
14026 * @param {String} query The SQL query to execute
14027 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14028 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14029 * saved in the current store (defaults to false)
14031 doQuery : function(q, forceAll){
14033 if(q === undefined || q === null){
14038 forceAll: forceAll,
14042 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14047 forceAll = qe.forceAll;
14048 if(forceAll === true || (q.length >= this.minChars)){
14050 this.hasQuery = true;
14052 if(this.lastQuery != q || this.alwaysQuery){
14053 this.lastQuery = q;
14054 if(this.mode == 'local'){
14055 this.selectedIndex = -1;
14057 this.store.clearFilter();
14060 if(this.specialFilter){
14061 this.fireEvent('specialfilter', this);
14066 this.store.filter(this.displayField, q);
14069 this.store.fireEvent("datachanged", this.store);
14076 this.store.baseParams[this.queryParam] = q;
14078 var options = {params : this.getParams(q)};
14081 options.add = true;
14082 options.params.start = this.page * this.pageSize;
14085 this.store.load(options);
14088 * this code will make the page width larger, at the beginning, the list not align correctly,
14089 * we should expand the list on onLoad
14090 * so command out it
14095 this.selectedIndex = -1;
14100 this.loadNext = false;
14104 getParams : function(q){
14106 //p[this.queryParam] = q;
14110 p.limit = this.pageSize;
14116 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14118 collapse : function(){
14119 if(!this.isExpanded()){
14125 this.hasFocus = false;
14129 this.cancelBtn.hide();
14130 this.trigger.show();
14133 this.tickableInputEl().dom.value = '';
14134 this.tickableInputEl().blur();
14139 Roo.get(document).un('mousedown', this.collapseIf, this);
14140 Roo.get(document).un('mousewheel', this.collapseIf, this);
14141 if (!this.editable) {
14142 Roo.get(document).un('keydown', this.listKeyPress, this);
14144 this.fireEvent('collapse', this);
14150 collapseIf : function(e){
14151 var in_combo = e.within(this.el);
14152 var in_list = e.within(this.list);
14153 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14155 if (in_combo || in_list || is_list) {
14156 //e.stopPropagation();
14161 this.onTickableFooterButtonClick(e, false, false);
14169 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14171 expand : function(){
14173 if(this.isExpanded() || !this.hasFocus){
14177 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14178 this.list.setWidth(lw);
14184 this.restrictHeight();
14188 this.tickItems = Roo.apply([], this.item);
14191 this.cancelBtn.show();
14192 this.trigger.hide();
14195 this.tickableInputEl().focus();
14200 Roo.get(document).on('mousedown', this.collapseIf, this);
14201 Roo.get(document).on('mousewheel', this.collapseIf, this);
14202 if (!this.editable) {
14203 Roo.get(document).on('keydown', this.listKeyPress, this);
14206 this.fireEvent('expand', this);
14210 // Implements the default empty TriggerField.onTriggerClick function
14211 onTriggerClick : function(e)
14213 Roo.log('trigger click');
14215 if(this.disabled || !this.triggerList){
14220 this.loadNext = false;
14222 if(this.isExpanded()){
14224 if (!this.blockFocus) {
14225 this.inputEl().focus();
14229 this.hasFocus = true;
14230 if(this.triggerAction == 'all') {
14231 this.doQuery(this.allQuery, true);
14233 this.doQuery(this.getRawValue());
14235 if (!this.blockFocus) {
14236 this.inputEl().focus();
14241 onTickableTriggerClick : function(e)
14248 this.loadNext = false;
14249 this.hasFocus = true;
14251 if(this.triggerAction == 'all') {
14252 this.doQuery(this.allQuery, true);
14254 this.doQuery(this.getRawValue());
14258 onSearchFieldClick : function(e)
14260 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14261 this.onTickableFooterButtonClick(e, false, false);
14265 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14270 this.loadNext = false;
14271 this.hasFocus = true;
14273 if(this.triggerAction == 'all') {
14274 this.doQuery(this.allQuery, true);
14276 this.doQuery(this.getRawValue());
14280 listKeyPress : function(e)
14282 //Roo.log('listkeypress');
14283 // scroll to first matching element based on key pres..
14284 if (e.isSpecialKey()) {
14287 var k = String.fromCharCode(e.getKey()).toUpperCase();
14290 var csel = this.view.getSelectedNodes();
14291 var cselitem = false;
14293 var ix = this.view.indexOf(csel[0]);
14294 cselitem = this.store.getAt(ix);
14295 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14301 this.store.each(function(v) {
14303 // start at existing selection.
14304 if (cselitem.id == v.id) {
14310 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14311 match = this.store.indexOf(v);
14317 if (match === false) {
14318 return true; // no more action?
14321 this.view.select(match);
14322 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14323 sn.scrollIntoView(sn.dom.parentNode, false);
14326 onViewScroll : function(e, t){
14328 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){
14332 this.hasQuery = true;
14334 this.loading = this.list.select('.loading', true).first();
14336 if(this.loading === null){
14337 this.list.createChild({
14339 cls: 'loading roo-select2-more-results roo-select2-active',
14340 html: 'Loading more results...'
14343 this.loading = this.list.select('.loading', true).first();
14345 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14347 this.loading.hide();
14350 this.loading.show();
14355 this.loadNext = true;
14357 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14362 addItem : function(o)
14364 var dv = ''; // display value
14366 if (this.displayField) {
14367 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14369 // this is an error condition!!!
14370 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14377 var choice = this.choices.createChild({
14379 cls: 'roo-select2-search-choice',
14388 cls: 'roo-select2-search-choice-close fa fa-times',
14393 }, this.searchField);
14395 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14397 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14405 this.inputEl().dom.value = '';
14410 onRemoveItem : function(e, _self, o)
14412 e.preventDefault();
14414 this.lastItem = Roo.apply([], this.item);
14416 var index = this.item.indexOf(o.data) * 1;
14419 Roo.log('not this item?!');
14423 this.item.splice(index, 1);
14428 this.fireEvent('remove', this, e);
14434 syncValue : function()
14436 if(!this.item.length){
14443 Roo.each(this.item, function(i){
14444 if(_this.valueField){
14445 value.push(i[_this.valueField]);
14452 this.value = value.join(',');
14454 if(this.hiddenField){
14455 this.hiddenField.dom.value = this.value;
14458 this.store.fireEvent("datachanged", this.store);
14463 clearItem : function()
14465 if(!this.multiple){
14471 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14479 if(this.tickable && !Roo.isTouch){
14480 this.view.refresh();
14484 inputEl: function ()
14486 if(Roo.isIOS && this.useNativeIOS){
14487 return this.el.select('select.roo-ios-select', true).first();
14490 if(Roo.isTouch && this.mobileTouchView){
14491 return this.el.select('input.form-control',true).first();
14495 return this.searchField;
14498 return this.el.select('input.form-control',true).first();
14501 onTickableFooterButtonClick : function(e, btn, el)
14503 e.preventDefault();
14505 this.lastItem = Roo.apply([], this.item);
14507 if(btn && btn.name == 'cancel'){
14508 this.tickItems = Roo.apply([], this.item);
14517 Roo.each(this.tickItems, function(o){
14525 validate : function()
14527 var v = this.getRawValue();
14530 v = this.getValue();
14533 if(this.disabled || this.allowBlank || v.length){
14538 this.markInvalid();
14542 tickableInputEl : function()
14544 if(!this.tickable || !this.editable){
14545 return this.inputEl();
14548 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14552 getAutoCreateTouchView : function()
14557 cls: 'form-group' //input-group
14563 type : this.inputType,
14564 cls : 'form-control x-combo-noedit',
14565 autocomplete: 'new-password',
14566 placeholder : this.placeholder || '',
14571 input.name = this.name;
14575 input.cls += ' input-' + this.size;
14578 if (this.disabled) {
14579 input.disabled = true;
14590 inputblock.cls += ' input-group';
14592 inputblock.cn.unshift({
14594 cls : 'input-group-addon',
14599 if(this.removable && !this.multiple){
14600 inputblock.cls += ' roo-removable';
14602 inputblock.cn.push({
14605 cls : 'roo-combo-removable-btn close'
14609 if(this.hasFeedback && !this.allowBlank){
14611 inputblock.cls += ' has-feedback';
14613 inputblock.cn.push({
14615 cls: 'glyphicon form-control-feedback'
14622 inputblock.cls += (this.before) ? '' : ' input-group';
14624 inputblock.cn.push({
14626 cls : 'input-group-addon',
14637 cls: 'form-hidden-field'
14651 cls: 'form-hidden-field'
14655 cls: 'roo-select2-choices',
14659 cls: 'roo-select2-search-field',
14672 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14678 if(!this.multiple && this.showToggleBtn){
14685 if (this.caret != false) {
14688 cls: 'fa fa-' + this.caret
14695 cls : 'input-group-addon btn dropdown-toggle',
14700 cls: 'combobox-clear',
14714 combobox.cls += ' roo-select2-container-multi';
14717 var align = this.labelAlign || this.parentLabelAlign();
14719 if (align ==='left' && this.fieldLabel.length) {
14724 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14725 tooltip : 'This field is required'
14729 cls : 'control-label',
14730 html : this.fieldLabel
14741 var labelCfg = cfg.cn[1];
14742 var contentCfg = cfg.cn[2];
14745 if(this.indicatorpos == 'right'){
14750 cls : 'control-label',
14754 html : this.fieldLabel
14758 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14759 tooltip : 'This field is required'
14772 labelCfg = cfg.cn[0];
14773 contentCfg = cfg.cn[1];
14778 if(this.labelWidth > 12){
14779 labelCfg.style = "width: " + this.labelWidth + 'px';
14782 if(this.labelWidth < 13 && this.labelmd == 0){
14783 this.labelmd = this.labelWidth;
14786 if(this.labellg > 0){
14787 labelCfg.cls += ' col-lg-' + this.labellg;
14788 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14791 if(this.labelmd > 0){
14792 labelCfg.cls += ' col-md-' + this.labelmd;
14793 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14796 if(this.labelsm > 0){
14797 labelCfg.cls += ' col-sm-' + this.labelsm;
14798 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14801 if(this.labelxs > 0){
14802 labelCfg.cls += ' col-xs-' + this.labelxs;
14803 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14807 } else if ( this.fieldLabel.length) {
14811 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14812 tooltip : 'This field is required'
14816 cls : 'control-label',
14817 html : this.fieldLabel
14828 if(this.indicatorpos == 'right'){
14832 cls : 'control-label',
14833 html : this.fieldLabel,
14837 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14838 tooltip : 'This field is required'
14855 var settings = this;
14857 ['xs','sm','md','lg'].map(function(size){
14858 if (settings[size]) {
14859 cfg.cls += ' col-' + size + '-' + settings[size];
14866 initTouchView : function()
14868 this.renderTouchView();
14870 this.touchViewEl.on('scroll', function(){
14871 this.el.dom.scrollTop = 0;
14874 this.originalValue = this.getValue();
14876 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14878 this.inputEl().on("click", this.showTouchView, this);
14879 if (this.triggerEl) {
14880 this.triggerEl.on("click", this.showTouchView, this);
14884 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14885 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14887 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14889 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14890 this.store.on('load', this.onTouchViewLoad, this);
14891 this.store.on('loadexception', this.onTouchViewLoadException, this);
14893 if(this.hiddenName){
14895 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14897 this.hiddenField.dom.value =
14898 this.hiddenValue !== undefined ? this.hiddenValue :
14899 this.value !== undefined ? this.value : '';
14901 this.el.dom.removeAttribute('name');
14902 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14906 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14907 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14910 if(this.removable && !this.multiple){
14911 var close = this.closeTriggerEl();
14913 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14914 close.on('click', this.removeBtnClick, this, close);
14918 * fix the bug in Safari iOS8
14920 this.inputEl().on("focus", function(e){
14921 document.activeElement.blur();
14929 renderTouchView : function()
14931 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14932 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14934 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14935 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14937 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14938 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14939 this.touchViewBodyEl.setStyle('overflow', 'auto');
14941 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14942 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14944 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14945 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14949 showTouchView : function()
14955 this.touchViewHeaderEl.hide();
14957 if(this.modalTitle.length){
14958 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14959 this.touchViewHeaderEl.show();
14962 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14963 this.touchViewEl.show();
14965 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
14967 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14968 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14970 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14972 if(this.modalTitle.length){
14973 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14976 this.touchViewBodyEl.setHeight(bodyHeight);
14980 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14982 this.touchViewEl.addClass('in');
14985 this.doTouchViewQuery();
14989 hideTouchView : function()
14991 this.touchViewEl.removeClass('in');
14995 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14997 this.touchViewEl.setStyle('display', 'none');
15002 setTouchViewValue : function()
15009 Roo.each(this.tickItems, function(o){
15014 this.hideTouchView();
15017 doTouchViewQuery : function()
15026 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15030 if(!this.alwaysQuery || this.mode == 'local'){
15031 this.onTouchViewLoad();
15038 onTouchViewBeforeLoad : function(combo,opts)
15044 onTouchViewLoad : function()
15046 if(this.store.getCount() < 1){
15047 this.onTouchViewEmptyResults();
15051 this.clearTouchView();
15053 var rawValue = this.getRawValue();
15055 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15057 this.tickItems = [];
15059 this.store.data.each(function(d, rowIndex){
15060 var row = this.touchViewListGroup.createChild(template);
15062 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15063 row.addClass(d.data.cls);
15066 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15069 html : d.data[this.displayField]
15072 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15073 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15076 row.removeClass('selected');
15077 if(!this.multiple && this.valueField &&
15078 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15081 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15082 row.addClass('selected');
15085 if(this.multiple && this.valueField &&
15086 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15090 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15091 this.tickItems.push(d.data);
15094 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15098 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15100 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15102 if(this.modalTitle.length){
15103 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15106 var listHeight = this.touchViewListGroup.getHeight();
15110 if(firstChecked && listHeight > bodyHeight){
15111 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15116 onTouchViewLoadException : function()
15118 this.hideTouchView();
15121 onTouchViewEmptyResults : function()
15123 this.clearTouchView();
15125 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15127 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15131 clearTouchView : function()
15133 this.touchViewListGroup.dom.innerHTML = '';
15136 onTouchViewClick : function(e, el, o)
15138 e.preventDefault();
15141 var rowIndex = o.rowIndex;
15143 var r = this.store.getAt(rowIndex);
15145 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15147 if(!this.multiple){
15148 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15149 c.dom.removeAttribute('checked');
15152 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15154 this.setFromData(r.data);
15156 var close = this.closeTriggerEl();
15162 this.hideTouchView();
15164 this.fireEvent('select', this, r, rowIndex);
15169 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15170 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15171 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15175 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15176 this.addItem(r.data);
15177 this.tickItems.push(r.data);
15181 getAutoCreateNativeIOS : function()
15184 cls: 'form-group' //input-group,
15189 cls : 'roo-ios-select'
15193 combobox.name = this.name;
15196 if (this.disabled) {
15197 combobox.disabled = true;
15200 var settings = this;
15202 ['xs','sm','md','lg'].map(function(size){
15203 if (settings[size]) {
15204 cfg.cls += ' col-' + size + '-' + settings[size];
15214 initIOSView : function()
15216 this.store.on('load', this.onIOSViewLoad, this);
15221 onIOSViewLoad : function()
15223 if(this.store.getCount() < 1){
15227 this.clearIOSView();
15229 if(this.allowBlank) {
15231 var default_text = '-- SELECT --';
15233 if(this.placeholder.length){
15234 default_text = this.placeholder;
15237 if(this.emptyTitle.length){
15238 default_text += ' - ' + this.emptyTitle + ' -';
15241 var opt = this.inputEl().createChild({
15244 html : default_text
15248 o[this.valueField] = 0;
15249 o[this.displayField] = default_text;
15251 this.ios_options.push({
15258 this.store.data.each(function(d, rowIndex){
15262 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15263 html = d.data[this.displayField];
15268 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15269 value = d.data[this.valueField];
15278 if(this.value == d.data[this.valueField]){
15279 option['selected'] = true;
15282 var opt = this.inputEl().createChild(option);
15284 this.ios_options.push({
15291 this.inputEl().on('change', function(){
15292 this.fireEvent('select', this);
15297 clearIOSView: function()
15299 this.inputEl().dom.innerHTML = '';
15301 this.ios_options = [];
15304 setIOSValue: function(v)
15308 if(!this.ios_options){
15312 Roo.each(this.ios_options, function(opts){
15314 opts.el.dom.removeAttribute('selected');
15316 if(opts.data[this.valueField] != v){
15320 opts.el.dom.setAttribute('selected', true);
15326 * @cfg {Boolean} grow
15330 * @cfg {Number} growMin
15334 * @cfg {Number} growMax
15343 Roo.apply(Roo.bootstrap.ComboBox, {
15347 cls: 'modal-header',
15369 cls: 'list-group-item',
15373 cls: 'roo-combobox-list-group-item-value'
15377 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15391 listItemCheckbox : {
15393 cls: 'list-group-item',
15397 cls: 'roo-combobox-list-group-item-value'
15401 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15417 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15422 cls: 'modal-footer',
15430 cls: 'col-xs-6 text-left',
15433 cls: 'btn btn-danger roo-touch-view-cancel',
15439 cls: 'col-xs-6 text-right',
15442 cls: 'btn btn-success roo-touch-view-ok',
15453 Roo.apply(Roo.bootstrap.ComboBox, {
15455 touchViewTemplate : {
15457 cls: 'modal fade roo-combobox-touch-view',
15461 cls: 'modal-dialog',
15462 style : 'position:fixed', // we have to fix position....
15466 cls: 'modal-content',
15468 Roo.bootstrap.ComboBox.header,
15469 Roo.bootstrap.ComboBox.body,
15470 Roo.bootstrap.ComboBox.footer
15479 * Ext JS Library 1.1.1
15480 * Copyright(c) 2006-2007, Ext JS, LLC.
15482 * Originally Released Under LGPL - original licence link has changed is not relivant.
15485 * <script type="text/javascript">
15490 * @extends Roo.util.Observable
15491 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15492 * This class also supports single and multi selection modes. <br>
15493 * Create a data model bound view:
15495 var store = new Roo.data.Store(...);
15497 var view = new Roo.View({
15499 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15501 singleSelect: true,
15502 selectedClass: "ydataview-selected",
15506 // listen for node click?
15507 view.on("click", function(vw, index, node, e){
15508 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15512 dataModel.load("foobar.xml");
15514 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15516 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15517 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15519 * Note: old style constructor is still suported (container, template, config)
15522 * Create a new View
15523 * @param {Object} config The config object
15526 Roo.View = function(config, depreciated_tpl, depreciated_config){
15528 this.parent = false;
15530 if (typeof(depreciated_tpl) == 'undefined') {
15531 // new way.. - universal constructor.
15532 Roo.apply(this, config);
15533 this.el = Roo.get(this.el);
15536 this.el = Roo.get(config);
15537 this.tpl = depreciated_tpl;
15538 Roo.apply(this, depreciated_config);
15540 this.wrapEl = this.el.wrap().wrap();
15541 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15544 if(typeof(this.tpl) == "string"){
15545 this.tpl = new Roo.Template(this.tpl);
15547 // support xtype ctors..
15548 this.tpl = new Roo.factory(this.tpl, Roo);
15552 this.tpl.compile();
15557 * @event beforeclick
15558 * Fires before a click is processed. Returns false to cancel the default action.
15559 * @param {Roo.View} this
15560 * @param {Number} index The index of the target node
15561 * @param {HTMLElement} node The target node
15562 * @param {Roo.EventObject} e The raw event object
15564 "beforeclick" : true,
15567 * Fires when a template node is clicked.
15568 * @param {Roo.View} this
15569 * @param {Number} index The index of the target node
15570 * @param {HTMLElement} node The target node
15571 * @param {Roo.EventObject} e The raw event object
15576 * Fires when a template node is double clicked.
15577 * @param {Roo.View} this
15578 * @param {Number} index The index of the target node
15579 * @param {HTMLElement} node The target node
15580 * @param {Roo.EventObject} e The raw event object
15584 * @event contextmenu
15585 * Fires when a template node is right clicked.
15586 * @param {Roo.View} this
15587 * @param {Number} index The index of the target node
15588 * @param {HTMLElement} node The target node
15589 * @param {Roo.EventObject} e The raw event object
15591 "contextmenu" : true,
15593 * @event selectionchange
15594 * Fires when the selected nodes change.
15595 * @param {Roo.View} this
15596 * @param {Array} selections Array of the selected nodes
15598 "selectionchange" : true,
15601 * @event beforeselect
15602 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15603 * @param {Roo.View} this
15604 * @param {HTMLElement} node The node to be selected
15605 * @param {Array} selections Array of currently selected nodes
15607 "beforeselect" : true,
15609 * @event preparedata
15610 * Fires on every row to render, to allow you to change the data.
15611 * @param {Roo.View} this
15612 * @param {Object} data to be rendered (change this)
15614 "preparedata" : true
15622 "click": this.onClick,
15623 "dblclick": this.onDblClick,
15624 "contextmenu": this.onContextMenu,
15628 this.selections = [];
15630 this.cmp = new Roo.CompositeElementLite([]);
15632 this.store = Roo.factory(this.store, Roo.data);
15633 this.setStore(this.store, true);
15636 if ( this.footer && this.footer.xtype) {
15638 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15640 this.footer.dataSource = this.store;
15641 this.footer.container = fctr;
15642 this.footer = Roo.factory(this.footer, Roo);
15643 fctr.insertFirst(this.el);
15645 // this is a bit insane - as the paging toolbar seems to detach the el..
15646 // dom.parentNode.parentNode.parentNode
15647 // they get detached?
15651 Roo.View.superclass.constructor.call(this);
15656 Roo.extend(Roo.View, Roo.util.Observable, {
15659 * @cfg {Roo.data.Store} store Data store to load data from.
15664 * @cfg {String|Roo.Element} el The container element.
15669 * @cfg {String|Roo.Template} tpl The template used by this View
15673 * @cfg {String} dataName the named area of the template to use as the data area
15674 * Works with domtemplates roo-name="name"
15678 * @cfg {String} selectedClass The css class to add to selected nodes
15680 selectedClass : "x-view-selected",
15682 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15687 * @cfg {String} text to display on mask (default Loading)
15691 * @cfg {Boolean} multiSelect Allow multiple selection
15693 multiSelect : false,
15695 * @cfg {Boolean} singleSelect Allow single selection
15697 singleSelect: false,
15700 * @cfg {Boolean} toggleSelect - selecting
15702 toggleSelect : false,
15705 * @cfg {Boolean} tickable - selecting
15710 * Returns the element this view is bound to.
15711 * @return {Roo.Element}
15713 getEl : function(){
15714 return this.wrapEl;
15720 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15722 refresh : function(){
15723 //Roo.log('refresh');
15726 // if we are using something like 'domtemplate', then
15727 // the what gets used is:
15728 // t.applySubtemplate(NAME, data, wrapping data..)
15729 // the outer template then get' applied with
15730 // the store 'extra data'
15731 // and the body get's added to the
15732 // roo-name="data" node?
15733 // <span class='roo-tpl-{name}'></span> ?????
15737 this.clearSelections();
15738 this.el.update("");
15740 var records = this.store.getRange();
15741 if(records.length < 1) {
15743 // is this valid?? = should it render a template??
15745 this.el.update(this.emptyText);
15749 if (this.dataName) {
15750 this.el.update(t.apply(this.store.meta)); //????
15751 el = this.el.child('.roo-tpl-' + this.dataName);
15754 for(var i = 0, len = records.length; i < len; i++){
15755 var data = this.prepareData(records[i].data, i, records[i]);
15756 this.fireEvent("preparedata", this, data, i, records[i]);
15758 var d = Roo.apply({}, data);
15761 Roo.apply(d, {'roo-id' : Roo.id()});
15765 Roo.each(this.parent.item, function(item){
15766 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15769 Roo.apply(d, {'roo-data-checked' : 'checked'});
15773 html[html.length] = Roo.util.Format.trim(
15775 t.applySubtemplate(this.dataName, d, this.store.meta) :
15782 el.update(html.join(""));
15783 this.nodes = el.dom.childNodes;
15784 this.updateIndexes(0);
15789 * Function to override to reformat the data that is sent to
15790 * the template for each node.
15791 * DEPRICATED - use the preparedata event handler.
15792 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15793 * a JSON object for an UpdateManager bound view).
15795 prepareData : function(data, index, record)
15797 this.fireEvent("preparedata", this, data, index, record);
15801 onUpdate : function(ds, record){
15802 // Roo.log('on update');
15803 this.clearSelections();
15804 var index = this.store.indexOf(record);
15805 var n = this.nodes[index];
15806 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15807 n.parentNode.removeChild(n);
15808 this.updateIndexes(index, index);
15814 onAdd : function(ds, records, index)
15816 //Roo.log(['on Add', ds, records, index] );
15817 this.clearSelections();
15818 if(this.nodes.length == 0){
15822 var n = this.nodes[index];
15823 for(var i = 0, len = records.length; i < len; i++){
15824 var d = this.prepareData(records[i].data, i, records[i]);
15826 this.tpl.insertBefore(n, d);
15829 this.tpl.append(this.el, d);
15832 this.updateIndexes(index);
15835 onRemove : function(ds, record, index){
15836 // Roo.log('onRemove');
15837 this.clearSelections();
15838 var el = this.dataName ?
15839 this.el.child('.roo-tpl-' + this.dataName) :
15842 el.dom.removeChild(this.nodes[index]);
15843 this.updateIndexes(index);
15847 * Refresh an individual node.
15848 * @param {Number} index
15850 refreshNode : function(index){
15851 this.onUpdate(this.store, this.store.getAt(index));
15854 updateIndexes : function(startIndex, endIndex){
15855 var ns = this.nodes;
15856 startIndex = startIndex || 0;
15857 endIndex = endIndex || ns.length - 1;
15858 for(var i = startIndex; i <= endIndex; i++){
15859 ns[i].nodeIndex = i;
15864 * Changes the data store this view uses and refresh the view.
15865 * @param {Store} store
15867 setStore : function(store, initial){
15868 if(!initial && this.store){
15869 this.store.un("datachanged", this.refresh);
15870 this.store.un("add", this.onAdd);
15871 this.store.un("remove", this.onRemove);
15872 this.store.un("update", this.onUpdate);
15873 this.store.un("clear", this.refresh);
15874 this.store.un("beforeload", this.onBeforeLoad);
15875 this.store.un("load", this.onLoad);
15876 this.store.un("loadexception", this.onLoad);
15880 store.on("datachanged", this.refresh, this);
15881 store.on("add", this.onAdd, this);
15882 store.on("remove", this.onRemove, this);
15883 store.on("update", this.onUpdate, this);
15884 store.on("clear", this.refresh, this);
15885 store.on("beforeload", this.onBeforeLoad, this);
15886 store.on("load", this.onLoad, this);
15887 store.on("loadexception", this.onLoad, this);
15895 * onbeforeLoad - masks the loading area.
15898 onBeforeLoad : function(store,opts)
15900 //Roo.log('onBeforeLoad');
15902 this.el.update("");
15904 this.el.mask(this.mask ? this.mask : "Loading" );
15906 onLoad : function ()
15913 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15914 * @param {HTMLElement} node
15915 * @return {HTMLElement} The template node
15917 findItemFromChild : function(node){
15918 var el = this.dataName ?
15919 this.el.child('.roo-tpl-' + this.dataName,true) :
15922 if(!node || node.parentNode == el){
15925 var p = node.parentNode;
15926 while(p && p != el){
15927 if(p.parentNode == el){
15936 onClick : function(e){
15937 var item = this.findItemFromChild(e.getTarget());
15939 var index = this.indexOf(item);
15940 if(this.onItemClick(item, index, e) !== false){
15941 this.fireEvent("click", this, index, item, e);
15944 this.clearSelections();
15949 onContextMenu : function(e){
15950 var item = this.findItemFromChild(e.getTarget());
15952 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15957 onDblClick : function(e){
15958 var item = this.findItemFromChild(e.getTarget());
15960 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15964 onItemClick : function(item, index, e)
15966 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15969 if (this.toggleSelect) {
15970 var m = this.isSelected(item) ? 'unselect' : 'select';
15973 _t[m](item, true, false);
15976 if(this.multiSelect || this.singleSelect){
15977 if(this.multiSelect && e.shiftKey && this.lastSelection){
15978 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15980 this.select(item, this.multiSelect && e.ctrlKey);
15981 this.lastSelection = item;
15984 if(!this.tickable){
15985 e.preventDefault();
15993 * Get the number of selected nodes.
15996 getSelectionCount : function(){
15997 return this.selections.length;
16001 * Get the currently selected nodes.
16002 * @return {Array} An array of HTMLElements
16004 getSelectedNodes : function(){
16005 return this.selections;
16009 * Get the indexes of the selected nodes.
16012 getSelectedIndexes : function(){
16013 var indexes = [], s = this.selections;
16014 for(var i = 0, len = s.length; i < len; i++){
16015 indexes.push(s[i].nodeIndex);
16021 * Clear all selections
16022 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16024 clearSelections : function(suppressEvent){
16025 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16026 this.cmp.elements = this.selections;
16027 this.cmp.removeClass(this.selectedClass);
16028 this.selections = [];
16029 if(!suppressEvent){
16030 this.fireEvent("selectionchange", this, this.selections);
16036 * Returns true if the passed node is selected
16037 * @param {HTMLElement/Number} node The node or node index
16038 * @return {Boolean}
16040 isSelected : function(node){
16041 var s = this.selections;
16045 node = this.getNode(node);
16046 return s.indexOf(node) !== -1;
16051 * @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
16052 * @param {Boolean} keepExisting (optional) true to keep existing selections
16053 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16055 select : function(nodeInfo, keepExisting, suppressEvent){
16056 if(nodeInfo instanceof Array){
16058 this.clearSelections(true);
16060 for(var i = 0, len = nodeInfo.length; i < len; i++){
16061 this.select(nodeInfo[i], true, true);
16065 var node = this.getNode(nodeInfo);
16066 if(!node || this.isSelected(node)){
16067 return; // already selected.
16070 this.clearSelections(true);
16073 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16074 Roo.fly(node).addClass(this.selectedClass);
16075 this.selections.push(node);
16076 if(!suppressEvent){
16077 this.fireEvent("selectionchange", this, this.selections);
16085 * @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
16086 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16087 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16089 unselect : function(nodeInfo, keepExisting, suppressEvent)
16091 if(nodeInfo instanceof Array){
16092 Roo.each(this.selections, function(s) {
16093 this.unselect(s, nodeInfo);
16097 var node = this.getNode(nodeInfo);
16098 if(!node || !this.isSelected(node)){
16099 //Roo.log("not selected");
16100 return; // not selected.
16104 Roo.each(this.selections, function(s) {
16106 Roo.fly(node).removeClass(this.selectedClass);
16113 this.selections= ns;
16114 this.fireEvent("selectionchange", this, this.selections);
16118 * Gets a template node.
16119 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16120 * @return {HTMLElement} The node or null if it wasn't found
16122 getNode : function(nodeInfo){
16123 if(typeof nodeInfo == "string"){
16124 return document.getElementById(nodeInfo);
16125 }else if(typeof nodeInfo == "number"){
16126 return this.nodes[nodeInfo];
16132 * Gets a range template nodes.
16133 * @param {Number} startIndex
16134 * @param {Number} endIndex
16135 * @return {Array} An array of nodes
16137 getNodes : function(start, end){
16138 var ns = this.nodes;
16139 start = start || 0;
16140 end = typeof end == "undefined" ? ns.length - 1 : end;
16143 for(var i = start; i <= end; i++){
16147 for(var i = start; i >= end; i--){
16155 * Finds the index of the passed node
16156 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16157 * @return {Number} The index of the node or -1
16159 indexOf : function(node){
16160 node = this.getNode(node);
16161 if(typeof node.nodeIndex == "number"){
16162 return node.nodeIndex;
16164 var ns = this.nodes;
16165 for(var i = 0, len = ns.length; i < len; i++){
16176 * based on jquery fullcalendar
16180 Roo.bootstrap = Roo.bootstrap || {};
16182 * @class Roo.bootstrap.Calendar
16183 * @extends Roo.bootstrap.Component
16184 * Bootstrap Calendar class
16185 * @cfg {Boolean} loadMask (true|false) default false
16186 * @cfg {Object} header generate the user specific header of the calendar, default false
16189 * Create a new Container
16190 * @param {Object} config The config object
16195 Roo.bootstrap.Calendar = function(config){
16196 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16200 * Fires when a date is selected
16201 * @param {DatePicker} this
16202 * @param {Date} date The selected date
16206 * @event monthchange
16207 * Fires when the displayed month changes
16208 * @param {DatePicker} this
16209 * @param {Date} date The selected month
16211 'monthchange': true,
16213 * @event evententer
16214 * Fires when mouse over an event
16215 * @param {Calendar} this
16216 * @param {event} Event
16218 'evententer': true,
16220 * @event eventleave
16221 * Fires when the mouse leaves an
16222 * @param {Calendar} this
16225 'eventleave': true,
16227 * @event eventclick
16228 * Fires when the mouse click an
16229 * @param {Calendar} this
16238 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16241 * @cfg {Number} startDay
16242 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16250 getAutoCreate : function(){
16253 var fc_button = function(name, corner, style, content ) {
16254 return Roo.apply({},{
16256 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16258 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16261 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16272 style : 'width:100%',
16279 cls : 'fc-header-left',
16281 fc_button('prev', 'left', 'arrow', '‹' ),
16282 fc_button('next', 'right', 'arrow', '›' ),
16283 { tag: 'span', cls: 'fc-header-space' },
16284 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16292 cls : 'fc-header-center',
16296 cls: 'fc-header-title',
16299 html : 'month / year'
16307 cls : 'fc-header-right',
16309 /* fc_button('month', 'left', '', 'month' ),
16310 fc_button('week', '', '', 'week' ),
16311 fc_button('day', 'right', '', 'day' )
16323 header = this.header;
16326 var cal_heads = function() {
16328 // fixme - handle this.
16330 for (var i =0; i < Date.dayNames.length; i++) {
16331 var d = Date.dayNames[i];
16334 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16335 html : d.substring(0,3)
16339 ret[0].cls += ' fc-first';
16340 ret[6].cls += ' fc-last';
16343 var cal_cell = function(n) {
16346 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16351 cls: 'fc-day-number',
16355 cls: 'fc-day-content',
16359 style: 'position: relative;' // height: 17px;
16371 var cal_rows = function() {
16374 for (var r = 0; r < 6; r++) {
16381 for (var i =0; i < Date.dayNames.length; i++) {
16382 var d = Date.dayNames[i];
16383 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16386 row.cn[0].cls+=' fc-first';
16387 row.cn[0].cn[0].style = 'min-height:90px';
16388 row.cn[6].cls+=' fc-last';
16392 ret[0].cls += ' fc-first';
16393 ret[4].cls += ' fc-prev-last';
16394 ret[5].cls += ' fc-last';
16401 cls: 'fc-border-separate',
16402 style : 'width:100%',
16410 cls : 'fc-first fc-last',
16428 cls : 'fc-content',
16429 style : "position: relative;",
16432 cls : 'fc-view fc-view-month fc-grid',
16433 style : 'position: relative',
16434 unselectable : 'on',
16437 cls : 'fc-event-container',
16438 style : 'position:absolute;z-index:8;top:0;left:0;'
16456 initEvents : function()
16459 throw "can not find store for calendar";
16465 style: "text-align:center",
16469 style: "background-color:white;width:50%;margin:250 auto",
16473 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16484 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16486 var size = this.el.select('.fc-content', true).first().getSize();
16487 this.maskEl.setSize(size.width, size.height);
16488 this.maskEl.enableDisplayMode("block");
16489 if(!this.loadMask){
16490 this.maskEl.hide();
16493 this.store = Roo.factory(this.store, Roo.data);
16494 this.store.on('load', this.onLoad, this);
16495 this.store.on('beforeload', this.onBeforeLoad, this);
16499 this.cells = this.el.select('.fc-day',true);
16500 //Roo.log(this.cells);
16501 this.textNodes = this.el.query('.fc-day-number');
16502 this.cells.addClassOnOver('fc-state-hover');
16504 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16505 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16506 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16507 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16509 this.on('monthchange', this.onMonthChange, this);
16511 this.update(new Date().clearTime());
16514 resize : function() {
16515 var sz = this.el.getSize();
16517 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16518 this.el.select('.fc-day-content div',true).setHeight(34);
16523 showPrevMonth : function(e){
16524 this.update(this.activeDate.add("mo", -1));
16526 showToday : function(e){
16527 this.update(new Date().clearTime());
16530 showNextMonth : function(e){
16531 this.update(this.activeDate.add("mo", 1));
16535 showPrevYear : function(){
16536 this.update(this.activeDate.add("y", -1));
16540 showNextYear : function(){
16541 this.update(this.activeDate.add("y", 1));
16546 update : function(date)
16548 var vd = this.activeDate;
16549 this.activeDate = date;
16550 // if(vd && this.el){
16551 // var t = date.getTime();
16552 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16553 // Roo.log('using add remove');
16555 // this.fireEvent('monthchange', this, date);
16557 // this.cells.removeClass("fc-state-highlight");
16558 // this.cells.each(function(c){
16559 // if(c.dateValue == t){
16560 // c.addClass("fc-state-highlight");
16561 // setTimeout(function(){
16562 // try{c.dom.firstChild.focus();}catch(e){}
16572 var days = date.getDaysInMonth();
16574 var firstOfMonth = date.getFirstDateOfMonth();
16575 var startingPos = firstOfMonth.getDay()-this.startDay;
16577 if(startingPos < this.startDay){
16581 var pm = date.add(Date.MONTH, -1);
16582 var prevStart = pm.getDaysInMonth()-startingPos;
16584 this.cells = this.el.select('.fc-day',true);
16585 this.textNodes = this.el.query('.fc-day-number');
16586 this.cells.addClassOnOver('fc-state-hover');
16588 var cells = this.cells.elements;
16589 var textEls = this.textNodes;
16591 Roo.each(cells, function(cell){
16592 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16595 days += startingPos;
16597 // convert everything to numbers so it's fast
16598 var day = 86400000;
16599 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16602 //Roo.log(prevStart);
16604 var today = new Date().clearTime().getTime();
16605 var sel = date.clearTime().getTime();
16606 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16607 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16608 var ddMatch = this.disabledDatesRE;
16609 var ddText = this.disabledDatesText;
16610 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16611 var ddaysText = this.disabledDaysText;
16612 var format = this.format;
16614 var setCellClass = function(cal, cell){
16618 //Roo.log('set Cell Class');
16620 var t = d.getTime();
16624 cell.dateValue = t;
16626 cell.className += " fc-today";
16627 cell.className += " fc-state-highlight";
16628 cell.title = cal.todayText;
16631 // disable highlight in other month..
16632 //cell.className += " fc-state-highlight";
16637 cell.className = " fc-state-disabled";
16638 cell.title = cal.minText;
16642 cell.className = " fc-state-disabled";
16643 cell.title = cal.maxText;
16647 if(ddays.indexOf(d.getDay()) != -1){
16648 cell.title = ddaysText;
16649 cell.className = " fc-state-disabled";
16652 if(ddMatch && format){
16653 var fvalue = d.dateFormat(format);
16654 if(ddMatch.test(fvalue)){
16655 cell.title = ddText.replace("%0", fvalue);
16656 cell.className = " fc-state-disabled";
16660 if (!cell.initialClassName) {
16661 cell.initialClassName = cell.dom.className;
16664 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16669 for(; i < startingPos; i++) {
16670 textEls[i].innerHTML = (++prevStart);
16671 d.setDate(d.getDate()+1);
16673 cells[i].className = "fc-past fc-other-month";
16674 setCellClass(this, cells[i]);
16679 for(; i < days; i++){
16680 intDay = i - startingPos + 1;
16681 textEls[i].innerHTML = (intDay);
16682 d.setDate(d.getDate()+1);
16684 cells[i].className = ''; // "x-date-active";
16685 setCellClass(this, cells[i]);
16689 for(; i < 42; i++) {
16690 textEls[i].innerHTML = (++extraDays);
16691 d.setDate(d.getDate()+1);
16693 cells[i].className = "fc-future fc-other-month";
16694 setCellClass(this, cells[i]);
16697 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16699 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16701 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16702 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16704 if(totalRows != 6){
16705 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16706 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16709 this.fireEvent('monthchange', this, date);
16713 if(!this.internalRender){
16714 var main = this.el.dom.firstChild;
16715 var w = main.offsetWidth;
16716 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16717 Roo.fly(main).setWidth(w);
16718 this.internalRender = true;
16719 // opera does not respect the auto grow header center column
16720 // then, after it gets a width opera refuses to recalculate
16721 // without a second pass
16722 if(Roo.isOpera && !this.secondPass){
16723 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16724 this.secondPass = true;
16725 this.update.defer(10, this, [date]);
16732 findCell : function(dt) {
16733 dt = dt.clearTime().getTime();
16735 this.cells.each(function(c){
16736 //Roo.log("check " +c.dateValue + '?=' + dt);
16737 if(c.dateValue == dt){
16747 findCells : function(ev) {
16748 var s = ev.start.clone().clearTime().getTime();
16750 var e= ev.end.clone().clearTime().getTime();
16753 this.cells.each(function(c){
16754 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16756 if(c.dateValue > e){
16759 if(c.dateValue < s){
16768 // findBestRow: function(cells)
16772 // for (var i =0 ; i < cells.length;i++) {
16773 // ret = Math.max(cells[i].rows || 0,ret);
16780 addItem : function(ev)
16782 // look for vertical location slot in
16783 var cells = this.findCells(ev);
16785 // ev.row = this.findBestRow(cells);
16787 // work out the location.
16791 for(var i =0; i < cells.length; i++) {
16793 cells[i].row = cells[0].row;
16796 cells[i].row = cells[i].row + 1;
16806 if (crow.start.getY() == cells[i].getY()) {
16808 crow.end = cells[i];
16825 cells[0].events.push(ev);
16827 this.calevents.push(ev);
16830 clearEvents: function() {
16832 if(!this.calevents){
16836 Roo.each(this.cells.elements, function(c){
16842 Roo.each(this.calevents, function(e) {
16843 Roo.each(e.els, function(el) {
16844 el.un('mouseenter' ,this.onEventEnter, this);
16845 el.un('mouseleave' ,this.onEventLeave, this);
16850 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16856 renderEvents: function()
16860 this.cells.each(function(c) {
16869 if(c.row != c.events.length){
16870 r = 4 - (4 - (c.row - c.events.length));
16873 c.events = ev.slice(0, r);
16874 c.more = ev.slice(r);
16876 if(c.more.length && c.more.length == 1){
16877 c.events.push(c.more.pop());
16880 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16884 this.cells.each(function(c) {
16886 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16889 for (var e = 0; e < c.events.length; e++){
16890 var ev = c.events[e];
16891 var rows = ev.rows;
16893 for(var i = 0; i < rows.length; i++) {
16895 // how many rows should it span..
16898 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16899 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16901 unselectable : "on",
16904 cls: 'fc-event-inner',
16908 // cls: 'fc-event-time',
16909 // html : cells.length > 1 ? '' : ev.time
16913 cls: 'fc-event-title',
16914 html : String.format('{0}', ev.title)
16921 cls: 'ui-resizable-handle ui-resizable-e',
16922 html : '  '
16929 cfg.cls += ' fc-event-start';
16931 if ((i+1) == rows.length) {
16932 cfg.cls += ' fc-event-end';
16935 var ctr = _this.el.select('.fc-event-container',true).first();
16936 var cg = ctr.createChild(cfg);
16938 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16939 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16941 var r = (c.more.length) ? 1 : 0;
16942 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16943 cg.setWidth(ebox.right - sbox.x -2);
16945 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16946 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16947 cg.on('click', _this.onEventClick, _this, ev);
16958 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16959 style : 'position: absolute',
16960 unselectable : "on",
16963 cls: 'fc-event-inner',
16967 cls: 'fc-event-title',
16975 cls: 'ui-resizable-handle ui-resizable-e',
16976 html : '  '
16982 var ctr = _this.el.select('.fc-event-container',true).first();
16983 var cg = ctr.createChild(cfg);
16985 var sbox = c.select('.fc-day-content',true).first().getBox();
16986 var ebox = c.select('.fc-day-content',true).first().getBox();
16988 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16989 cg.setWidth(ebox.right - sbox.x -2);
16991 cg.on('click', _this.onMoreEventClick, _this, c.more);
17001 onEventEnter: function (e, el,event,d) {
17002 this.fireEvent('evententer', this, el, event);
17005 onEventLeave: function (e, el,event,d) {
17006 this.fireEvent('eventleave', this, el, event);
17009 onEventClick: function (e, el,event,d) {
17010 this.fireEvent('eventclick', this, el, event);
17013 onMonthChange: function () {
17017 onMoreEventClick: function(e, el, more)
17021 this.calpopover.placement = 'right';
17022 this.calpopover.setTitle('More');
17024 this.calpopover.setContent('');
17026 var ctr = this.calpopover.el.select('.popover-content', true).first();
17028 Roo.each(more, function(m){
17030 cls : 'fc-event-hori fc-event-draggable',
17033 var cg = ctr.createChild(cfg);
17035 cg.on('click', _this.onEventClick, _this, m);
17038 this.calpopover.show(el);
17043 onLoad: function ()
17045 this.calevents = [];
17048 if(this.store.getCount() > 0){
17049 this.store.data.each(function(d){
17052 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17053 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17054 time : d.data.start_time,
17055 title : d.data.title,
17056 description : d.data.description,
17057 venue : d.data.venue
17062 this.renderEvents();
17064 if(this.calevents.length && this.loadMask){
17065 this.maskEl.hide();
17069 onBeforeLoad: function()
17071 this.clearEvents();
17073 this.maskEl.show();
17087 * @class Roo.bootstrap.Popover
17088 * @extends Roo.bootstrap.Component
17089 * Bootstrap Popover class
17090 * @cfg {String} html contents of the popover (or false to use children..)
17091 * @cfg {String} title of popover (or false to hide)
17092 * @cfg {String} placement how it is placed
17093 * @cfg {String} trigger click || hover (or false to trigger manually)
17094 * @cfg {String} over what (parent or false to trigger manually.)
17095 * @cfg {Number} delay - delay before showing
17098 * Create a new Popover
17099 * @param {Object} config The config object
17102 Roo.bootstrap.Popover = function(config){
17103 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17109 * After the popover show
17111 * @param {Roo.bootstrap.Popover} this
17116 * After the popover hide
17118 * @param {Roo.bootstrap.Popover} this
17124 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17126 title: 'Fill in a title',
17129 placement : 'right',
17130 trigger : 'hover', // hover
17136 can_build_overlaid : false,
17138 getChildContainer : function()
17140 return this.el.select('.popover-content',true).first();
17143 getAutoCreate : function(){
17146 cls : 'popover roo-dynamic',
17147 style: 'display:block',
17153 cls : 'popover-inner',
17157 cls: 'popover-title',
17161 cls : 'popover-content',
17172 setTitle: function(str)
17175 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17177 setContent: function(str)
17180 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17182 // as it get's added to the bottom of the page.
17183 onRender : function(ct, position)
17185 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17187 var cfg = Roo.apply({}, this.getAutoCreate());
17191 cfg.cls += ' ' + this.cls;
17194 cfg.style = this.style;
17196 //Roo.log("adding to ");
17197 this.el = Roo.get(document.body).createChild(cfg, position);
17198 // Roo.log(this.el);
17203 initEvents : function()
17205 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17206 this.el.enableDisplayMode('block');
17208 if (this.over === false) {
17211 if (this.triggers === false) {
17214 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17215 var triggers = this.trigger ? this.trigger.split(' ') : [];
17216 Roo.each(triggers, function(trigger) {
17218 if (trigger == 'click') {
17219 on_el.on('click', this.toggle, this);
17220 } else if (trigger != 'manual') {
17221 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17222 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17224 on_el.on(eventIn ,this.enter, this);
17225 on_el.on(eventOut, this.leave, this);
17236 toggle : function () {
17237 this.hoverState == 'in' ? this.leave() : this.enter();
17240 enter : function () {
17242 clearTimeout(this.timeout);
17244 this.hoverState = 'in';
17246 if (!this.delay || !this.delay.show) {
17251 this.timeout = setTimeout(function () {
17252 if (_t.hoverState == 'in') {
17255 }, this.delay.show)
17258 leave : function() {
17259 clearTimeout(this.timeout);
17261 this.hoverState = 'out';
17263 if (!this.delay || !this.delay.hide) {
17268 this.timeout = setTimeout(function () {
17269 if (_t.hoverState == 'out') {
17272 }, this.delay.hide)
17275 show : function (on_el)
17278 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17282 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17283 if (this.html !== false) {
17284 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17286 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17287 if (!this.title.length) {
17288 this.el.select('.popover-title',true).hide();
17291 var placement = typeof this.placement == 'function' ?
17292 this.placement.call(this, this.el, on_el) :
17295 var autoToken = /\s?auto?\s?/i;
17296 var autoPlace = autoToken.test(placement);
17298 placement = placement.replace(autoToken, '') || 'top';
17302 //this.el.setXY([0,0]);
17304 this.el.dom.style.display='block';
17305 this.el.addClass(placement);
17307 //this.el.appendTo(on_el);
17309 var p = this.getPosition();
17310 var box = this.el.getBox();
17315 var align = Roo.bootstrap.Popover.alignment[placement];
17316 this.el.alignTo(on_el, align[0],align[1]);
17317 //var arrow = this.el.select('.arrow',true).first();
17318 //arrow.set(align[2],
17320 this.el.addClass('in');
17323 if (this.el.hasClass('fade')) {
17327 this.hoverState = 'in';
17329 this.fireEvent('show', this);
17334 this.el.setXY([0,0]);
17335 this.el.removeClass('in');
17337 this.hoverState = null;
17339 this.fireEvent('hide', this);
17344 Roo.bootstrap.Popover.alignment = {
17345 'left' : ['r-l', [-10,0], 'right'],
17346 'right' : ['l-r', [10,0], 'left'],
17347 'bottom' : ['t-b', [0,10], 'top'],
17348 'top' : [ 'b-t', [0,-10], 'bottom']
17359 * @class Roo.bootstrap.Progress
17360 * @extends Roo.bootstrap.Component
17361 * Bootstrap Progress class
17362 * @cfg {Boolean} striped striped of the progress bar
17363 * @cfg {Boolean} active animated of the progress bar
17367 * Create a new Progress
17368 * @param {Object} config The config object
17371 Roo.bootstrap.Progress = function(config){
17372 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17375 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17380 getAutoCreate : function(){
17388 cfg.cls += ' progress-striped';
17392 cfg.cls += ' active';
17411 * @class Roo.bootstrap.ProgressBar
17412 * @extends Roo.bootstrap.Component
17413 * Bootstrap ProgressBar class
17414 * @cfg {Number} aria_valuenow aria-value now
17415 * @cfg {Number} aria_valuemin aria-value min
17416 * @cfg {Number} aria_valuemax aria-value max
17417 * @cfg {String} label label for the progress bar
17418 * @cfg {String} panel (success | info | warning | danger )
17419 * @cfg {String} role role of the progress bar
17420 * @cfg {String} sr_only text
17424 * Create a new ProgressBar
17425 * @param {Object} config The config object
17428 Roo.bootstrap.ProgressBar = function(config){
17429 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17432 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17436 aria_valuemax : 100,
17442 getAutoCreate : function()
17447 cls: 'progress-bar',
17448 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17460 cfg.role = this.role;
17463 if(this.aria_valuenow){
17464 cfg['aria-valuenow'] = this.aria_valuenow;
17467 if(this.aria_valuemin){
17468 cfg['aria-valuemin'] = this.aria_valuemin;
17471 if(this.aria_valuemax){
17472 cfg['aria-valuemax'] = this.aria_valuemax;
17475 if(this.label && !this.sr_only){
17476 cfg.html = this.label;
17480 cfg.cls += ' progress-bar-' + this.panel;
17486 update : function(aria_valuenow)
17488 this.aria_valuenow = aria_valuenow;
17490 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17505 * @class Roo.bootstrap.TabGroup
17506 * @extends Roo.bootstrap.Column
17507 * Bootstrap Column class
17508 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17509 * @cfg {Boolean} carousel true to make the group behave like a carousel
17510 * @cfg {Boolean} bullets show bullets for the panels
17511 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17512 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17513 * @cfg {Boolean} showarrow (true|false) show arrow default true
17516 * Create a new TabGroup
17517 * @param {Object} config The config object
17520 Roo.bootstrap.TabGroup = function(config){
17521 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17523 this.navId = Roo.id();
17526 Roo.bootstrap.TabGroup.register(this);
17530 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17533 transition : false,
17538 slideOnTouch : false,
17541 getAutoCreate : function()
17543 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17545 cfg.cls += ' tab-content';
17547 if (this.carousel) {
17548 cfg.cls += ' carousel slide';
17551 cls : 'carousel-inner',
17555 if(this.bullets && !Roo.isTouch){
17558 cls : 'carousel-bullets',
17562 if(this.bullets_cls){
17563 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17570 cfg.cn[0].cn.push(bullets);
17573 if(this.showarrow){
17574 cfg.cn[0].cn.push({
17576 class : 'carousel-arrow',
17580 class : 'carousel-prev',
17584 class : 'fa fa-chevron-left'
17590 class : 'carousel-next',
17594 class : 'fa fa-chevron-right'
17607 initEvents: function()
17609 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17610 // this.el.on("touchstart", this.onTouchStart, this);
17613 if(this.autoslide){
17616 this.slideFn = window.setInterval(function() {
17617 _this.showPanelNext();
17621 if(this.showarrow){
17622 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17623 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17629 // onTouchStart : function(e, el, o)
17631 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17635 // this.showPanelNext();
17639 getChildContainer : function()
17641 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17645 * register a Navigation item
17646 * @param {Roo.bootstrap.NavItem} the navitem to add
17648 register : function(item)
17650 this.tabs.push( item);
17651 item.navId = this.navId; // not really needed..
17656 getActivePanel : function()
17659 Roo.each(this.tabs, function(t) {
17669 getPanelByName : function(n)
17672 Roo.each(this.tabs, function(t) {
17673 if (t.tabId == n) {
17681 indexOfPanel : function(p)
17684 Roo.each(this.tabs, function(t,i) {
17685 if (t.tabId == p.tabId) {
17694 * show a specific panel
17695 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17696 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17698 showPanel : function (pan)
17700 if(this.transition || typeof(pan) == 'undefined'){
17701 Roo.log("waiting for the transitionend");
17705 if (typeof(pan) == 'number') {
17706 pan = this.tabs[pan];
17709 if (typeof(pan) == 'string') {
17710 pan = this.getPanelByName(pan);
17713 var cur = this.getActivePanel();
17716 Roo.log('pan or acitve pan is undefined');
17720 if (pan.tabId == this.getActivePanel().tabId) {
17724 if (false === cur.fireEvent('beforedeactivate')) {
17728 if(this.bullets > 0 && !Roo.isTouch){
17729 this.setActiveBullet(this.indexOfPanel(pan));
17732 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17734 this.transition = true;
17735 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17736 var lr = dir == 'next' ? 'left' : 'right';
17737 pan.el.addClass(dir); // or prev
17738 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17739 cur.el.addClass(lr); // or right
17740 pan.el.addClass(lr);
17743 cur.el.on('transitionend', function() {
17744 Roo.log("trans end?");
17746 pan.el.removeClass([lr,dir]);
17747 pan.setActive(true);
17749 cur.el.removeClass([lr]);
17750 cur.setActive(false);
17752 _this.transition = false;
17754 }, this, { single: true } );
17759 cur.setActive(false);
17760 pan.setActive(true);
17765 showPanelNext : function()
17767 var i = this.indexOfPanel(this.getActivePanel());
17769 if (i >= this.tabs.length - 1 && !this.autoslide) {
17773 if (i >= this.tabs.length - 1 && this.autoslide) {
17777 this.showPanel(this.tabs[i+1]);
17780 showPanelPrev : function()
17782 var i = this.indexOfPanel(this.getActivePanel());
17784 if (i < 1 && !this.autoslide) {
17788 if (i < 1 && this.autoslide) {
17789 i = this.tabs.length;
17792 this.showPanel(this.tabs[i-1]);
17796 addBullet: function()
17798 if(!this.bullets || Roo.isTouch){
17801 var ctr = this.el.select('.carousel-bullets',true).first();
17802 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17803 var bullet = ctr.createChild({
17804 cls : 'bullet bullet-' + i
17805 },ctr.dom.lastChild);
17810 bullet.on('click', (function(e, el, o, ii, t){
17812 e.preventDefault();
17814 this.showPanel(ii);
17816 if(this.autoslide && this.slideFn){
17817 clearInterval(this.slideFn);
17818 this.slideFn = window.setInterval(function() {
17819 _this.showPanelNext();
17823 }).createDelegate(this, [i, bullet], true));
17828 setActiveBullet : function(i)
17834 Roo.each(this.el.select('.bullet', true).elements, function(el){
17835 el.removeClass('selected');
17838 var bullet = this.el.select('.bullet-' + i, true).first();
17844 bullet.addClass('selected');
17855 Roo.apply(Roo.bootstrap.TabGroup, {
17859 * register a Navigation Group
17860 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17862 register : function(navgrp)
17864 this.groups[navgrp.navId] = navgrp;
17868 * fetch a Navigation Group based on the navigation ID
17869 * if one does not exist , it will get created.
17870 * @param {string} the navgroup to add
17871 * @returns {Roo.bootstrap.NavGroup} the navgroup
17873 get: function(navId) {
17874 if (typeof(this.groups[navId]) == 'undefined') {
17875 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17877 return this.groups[navId] ;
17892 * @class Roo.bootstrap.TabPanel
17893 * @extends Roo.bootstrap.Component
17894 * Bootstrap TabPanel class
17895 * @cfg {Boolean} active panel active
17896 * @cfg {String} html panel content
17897 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17898 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17899 * @cfg {String} href click to link..
17903 * Create a new TabPanel
17904 * @param {Object} config The config object
17907 Roo.bootstrap.TabPanel = function(config){
17908 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17912 * Fires when the active status changes
17913 * @param {Roo.bootstrap.TabPanel} this
17914 * @param {Boolean} state the new state
17919 * @event beforedeactivate
17920 * Fires before a tab is de-activated - can be used to do validation on a form.
17921 * @param {Roo.bootstrap.TabPanel} this
17922 * @return {Boolean} false if there is an error
17925 'beforedeactivate': true
17928 this.tabId = this.tabId || Roo.id();
17932 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17940 getAutoCreate : function(){
17943 // item is needed for carousel - not sure if it has any effect otherwise
17944 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17945 html: this.html || ''
17949 cfg.cls += ' active';
17953 cfg.tabId = this.tabId;
17960 initEvents: function()
17962 var p = this.parent();
17964 this.navId = this.navId || p.navId;
17966 if (typeof(this.navId) != 'undefined') {
17967 // not really needed.. but just in case.. parent should be a NavGroup.
17968 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17972 var i = tg.tabs.length - 1;
17974 if(this.active && tg.bullets > 0 && i < tg.bullets){
17975 tg.setActiveBullet(i);
17979 this.el.on('click', this.onClick, this);
17982 this.el.on("touchstart", this.onTouchStart, this);
17983 this.el.on("touchmove", this.onTouchMove, this);
17984 this.el.on("touchend", this.onTouchEnd, this);
17989 onRender : function(ct, position)
17991 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17994 setActive : function(state)
17996 Roo.log("panel - set active " + this.tabId + "=" + state);
17998 this.active = state;
18000 this.el.removeClass('active');
18002 } else if (!this.el.hasClass('active')) {
18003 this.el.addClass('active');
18006 this.fireEvent('changed', this, state);
18009 onClick : function(e)
18011 e.preventDefault();
18013 if(!this.href.length){
18017 window.location.href = this.href;
18026 onTouchStart : function(e)
18028 this.swiping = false;
18030 this.startX = e.browserEvent.touches[0].clientX;
18031 this.startY = e.browserEvent.touches[0].clientY;
18034 onTouchMove : function(e)
18036 this.swiping = true;
18038 this.endX = e.browserEvent.touches[0].clientX;
18039 this.endY = e.browserEvent.touches[0].clientY;
18042 onTouchEnd : function(e)
18049 var tabGroup = this.parent();
18051 if(this.endX > this.startX){ // swiping right
18052 tabGroup.showPanelPrev();
18056 if(this.startX > this.endX){ // swiping left
18057 tabGroup.showPanelNext();
18076 * @class Roo.bootstrap.DateField
18077 * @extends Roo.bootstrap.Input
18078 * Bootstrap DateField class
18079 * @cfg {Number} weekStart default 0
18080 * @cfg {String} viewMode default empty, (months|years)
18081 * @cfg {String} minViewMode default empty, (months|years)
18082 * @cfg {Number} startDate default -Infinity
18083 * @cfg {Number} endDate default Infinity
18084 * @cfg {Boolean} todayHighlight default false
18085 * @cfg {Boolean} todayBtn default false
18086 * @cfg {Boolean} calendarWeeks default false
18087 * @cfg {Object} daysOfWeekDisabled default empty
18088 * @cfg {Boolean} singleMode default false (true | false)
18090 * @cfg {Boolean} keyboardNavigation default true
18091 * @cfg {String} language default en
18094 * Create a new DateField
18095 * @param {Object} config The config object
18098 Roo.bootstrap.DateField = function(config){
18099 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18103 * Fires when this field show.
18104 * @param {Roo.bootstrap.DateField} this
18105 * @param {Mixed} date The date value
18110 * Fires when this field hide.
18111 * @param {Roo.bootstrap.DateField} this
18112 * @param {Mixed} date The date value
18117 * Fires when select a date.
18118 * @param {Roo.bootstrap.DateField} this
18119 * @param {Mixed} date The date value
18123 * @event beforeselect
18124 * Fires when before select a date.
18125 * @param {Roo.bootstrap.DateField} this
18126 * @param {Mixed} date The date value
18128 beforeselect : true
18132 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18135 * @cfg {String} format
18136 * The default date format string which can be overriden for localization support. The format must be
18137 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18141 * @cfg {String} altFormats
18142 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18143 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18145 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18153 todayHighlight : false,
18159 keyboardNavigation: true,
18161 calendarWeeks: false,
18163 startDate: -Infinity,
18167 daysOfWeekDisabled: [],
18171 singleMode : false,
18173 UTCDate: function()
18175 return new Date(Date.UTC.apply(Date, arguments));
18178 UTCToday: function()
18180 var today = new Date();
18181 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18184 getDate: function() {
18185 var d = this.getUTCDate();
18186 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18189 getUTCDate: function() {
18193 setDate: function(d) {
18194 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18197 setUTCDate: function(d) {
18199 this.setValue(this.formatDate(this.date));
18202 onRender: function(ct, position)
18205 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18207 this.language = this.language || 'en';
18208 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18209 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18211 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18212 this.format = this.format || 'm/d/y';
18213 this.isInline = false;
18214 this.isInput = true;
18215 this.component = this.el.select('.add-on', true).first() || false;
18216 this.component = (this.component && this.component.length === 0) ? false : this.component;
18217 this.hasInput = this.component && this.inputEl().length;
18219 if (typeof(this.minViewMode === 'string')) {
18220 switch (this.minViewMode) {
18222 this.minViewMode = 1;
18225 this.minViewMode = 2;
18228 this.minViewMode = 0;
18233 if (typeof(this.viewMode === 'string')) {
18234 switch (this.viewMode) {
18247 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18249 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18251 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18253 this.picker().on('mousedown', this.onMousedown, this);
18254 this.picker().on('click', this.onClick, this);
18256 this.picker().addClass('datepicker-dropdown');
18258 this.startViewMode = this.viewMode;
18260 if(this.singleMode){
18261 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18262 v.setVisibilityMode(Roo.Element.DISPLAY);
18266 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18267 v.setStyle('width', '189px');
18271 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18272 if(!this.calendarWeeks){
18277 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18278 v.attr('colspan', function(i, val){
18279 return parseInt(val) + 1;
18284 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18286 this.setStartDate(this.startDate);
18287 this.setEndDate(this.endDate);
18289 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18296 if(this.isInline) {
18301 picker : function()
18303 return this.pickerEl;
18304 // return this.el.select('.datepicker', true).first();
18307 fillDow: function()
18309 var dowCnt = this.weekStart;
18318 if(this.calendarWeeks){
18326 while (dowCnt < this.weekStart + 7) {
18330 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18334 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18337 fillMonths: function()
18340 var months = this.picker().select('>.datepicker-months td', true).first();
18342 months.dom.innerHTML = '';
18348 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18351 months.createChild(month);
18358 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;
18360 if (this.date < this.startDate) {
18361 this.viewDate = new Date(this.startDate);
18362 } else if (this.date > this.endDate) {
18363 this.viewDate = new Date(this.endDate);
18365 this.viewDate = new Date(this.date);
18373 var d = new Date(this.viewDate),
18374 year = d.getUTCFullYear(),
18375 month = d.getUTCMonth(),
18376 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18377 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18378 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18379 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18380 currentDate = this.date && this.date.valueOf(),
18381 today = this.UTCToday();
18383 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18385 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18387 // this.picker.select('>tfoot th.today').
18388 // .text(dates[this.language].today)
18389 // .toggle(this.todayBtn !== false);
18391 this.updateNavArrows();
18394 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18396 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18398 prevMonth.setUTCDate(day);
18400 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18402 var nextMonth = new Date(prevMonth);
18404 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18406 nextMonth = nextMonth.valueOf();
18408 var fillMonths = false;
18410 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18412 while(prevMonth.valueOf() < nextMonth) {
18415 if (prevMonth.getUTCDay() === this.weekStart) {
18417 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18425 if(this.calendarWeeks){
18426 // ISO 8601: First week contains first thursday.
18427 // ISO also states week starts on Monday, but we can be more abstract here.
18429 // Start of current week: based on weekstart/current date
18430 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18431 // Thursday of this week
18432 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18433 // First Thursday of year, year from thursday
18434 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18435 // Calendar week: ms between thursdays, div ms per day, div 7 days
18436 calWeek = (th - yth) / 864e5 / 7 + 1;
18438 fillMonths.cn.push({
18446 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18448 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18451 if (this.todayHighlight &&
18452 prevMonth.getUTCFullYear() == today.getFullYear() &&
18453 prevMonth.getUTCMonth() == today.getMonth() &&
18454 prevMonth.getUTCDate() == today.getDate()) {
18455 clsName += ' today';
18458 if (currentDate && prevMonth.valueOf() === currentDate) {
18459 clsName += ' active';
18462 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18463 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18464 clsName += ' disabled';
18467 fillMonths.cn.push({
18469 cls: 'day ' + clsName,
18470 html: prevMonth.getDate()
18473 prevMonth.setDate(prevMonth.getDate()+1);
18476 var currentYear = this.date && this.date.getUTCFullYear();
18477 var currentMonth = this.date && this.date.getUTCMonth();
18479 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18481 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18482 v.removeClass('active');
18484 if(currentYear === year && k === currentMonth){
18485 v.addClass('active');
18488 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18489 v.addClass('disabled');
18495 year = parseInt(year/10, 10) * 10;
18497 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18499 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18502 for (var i = -1; i < 11; i++) {
18503 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18505 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18513 showMode: function(dir)
18516 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18519 Roo.each(this.picker().select('>div',true).elements, function(v){
18520 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18523 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18528 if(this.isInline) {
18532 this.picker().removeClass(['bottom', 'top']);
18534 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18536 * place to the top of element!
18540 this.picker().addClass('top');
18541 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18546 this.picker().addClass('bottom');
18548 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18551 parseDate : function(value)
18553 if(!value || value instanceof Date){
18556 var v = Date.parseDate(value, this.format);
18557 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18558 v = Date.parseDate(value, 'Y-m-d');
18560 if(!v && this.altFormats){
18561 if(!this.altFormatsArray){
18562 this.altFormatsArray = this.altFormats.split("|");
18564 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18565 v = Date.parseDate(value, this.altFormatsArray[i]);
18571 formatDate : function(date, fmt)
18573 return (!date || !(date instanceof Date)) ?
18574 date : date.dateFormat(fmt || this.format);
18577 onFocus : function()
18579 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18583 onBlur : function()
18585 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18587 var d = this.inputEl().getValue();
18596 this.picker().show();
18600 this.fireEvent('show', this, this.date);
18605 if(this.isInline) {
18608 this.picker().hide();
18609 this.viewMode = this.startViewMode;
18612 this.fireEvent('hide', this, this.date);
18616 onMousedown: function(e)
18618 e.stopPropagation();
18619 e.preventDefault();
18624 Roo.bootstrap.DateField.superclass.keyup.call(this);
18628 setValue: function(v)
18630 if(this.fireEvent('beforeselect', this, v) !== false){
18631 var d = new Date(this.parseDate(v) ).clearTime();
18633 if(isNaN(d.getTime())){
18634 this.date = this.viewDate = '';
18635 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18639 v = this.formatDate(d);
18641 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18643 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18647 this.fireEvent('select', this, this.date);
18651 getValue: function()
18653 return this.formatDate(this.date);
18656 fireKey: function(e)
18658 if (!this.picker().isVisible()){
18659 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18665 var dateChanged = false,
18667 newDate, newViewDate;
18672 e.preventDefault();
18676 if (!this.keyboardNavigation) {
18679 dir = e.keyCode == 37 ? -1 : 1;
18682 newDate = this.moveYear(this.date, dir);
18683 newViewDate = this.moveYear(this.viewDate, dir);
18684 } else if (e.shiftKey){
18685 newDate = this.moveMonth(this.date, dir);
18686 newViewDate = this.moveMonth(this.viewDate, dir);
18688 newDate = new Date(this.date);
18689 newDate.setUTCDate(this.date.getUTCDate() + dir);
18690 newViewDate = new Date(this.viewDate);
18691 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18693 if (this.dateWithinRange(newDate)){
18694 this.date = newDate;
18695 this.viewDate = newViewDate;
18696 this.setValue(this.formatDate(this.date));
18698 e.preventDefault();
18699 dateChanged = true;
18704 if (!this.keyboardNavigation) {
18707 dir = e.keyCode == 38 ? -1 : 1;
18709 newDate = this.moveYear(this.date, dir);
18710 newViewDate = this.moveYear(this.viewDate, dir);
18711 } else if (e.shiftKey){
18712 newDate = this.moveMonth(this.date, dir);
18713 newViewDate = this.moveMonth(this.viewDate, dir);
18715 newDate = new Date(this.date);
18716 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18717 newViewDate = new Date(this.viewDate);
18718 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18720 if (this.dateWithinRange(newDate)){
18721 this.date = newDate;
18722 this.viewDate = newViewDate;
18723 this.setValue(this.formatDate(this.date));
18725 e.preventDefault();
18726 dateChanged = true;
18730 this.setValue(this.formatDate(this.date));
18732 e.preventDefault();
18735 this.setValue(this.formatDate(this.date));
18749 onClick: function(e)
18751 e.stopPropagation();
18752 e.preventDefault();
18754 var target = e.getTarget();
18756 if(target.nodeName.toLowerCase() === 'i'){
18757 target = Roo.get(target).dom.parentNode;
18760 var nodeName = target.nodeName;
18761 var className = target.className;
18762 var html = target.innerHTML;
18763 //Roo.log(nodeName);
18765 switch(nodeName.toLowerCase()) {
18767 switch(className) {
18773 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18774 switch(this.viewMode){
18776 this.viewDate = this.moveMonth(this.viewDate, dir);
18780 this.viewDate = this.moveYear(this.viewDate, dir);
18786 var date = new Date();
18787 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18789 this.setValue(this.formatDate(this.date));
18796 if (className.indexOf('disabled') < 0) {
18797 this.viewDate.setUTCDate(1);
18798 if (className.indexOf('month') > -1) {
18799 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18801 var year = parseInt(html, 10) || 0;
18802 this.viewDate.setUTCFullYear(year);
18806 if(this.singleMode){
18807 this.setValue(this.formatDate(this.viewDate));
18818 //Roo.log(className);
18819 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18820 var day = parseInt(html, 10) || 1;
18821 var year = this.viewDate.getUTCFullYear(),
18822 month = this.viewDate.getUTCMonth();
18824 if (className.indexOf('old') > -1) {
18831 } else if (className.indexOf('new') > -1) {
18839 //Roo.log([year,month,day]);
18840 this.date = this.UTCDate(year, month, day,0,0,0,0);
18841 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18843 //Roo.log(this.formatDate(this.date));
18844 this.setValue(this.formatDate(this.date));
18851 setStartDate: function(startDate)
18853 this.startDate = startDate || -Infinity;
18854 if (this.startDate !== -Infinity) {
18855 this.startDate = this.parseDate(this.startDate);
18858 this.updateNavArrows();
18861 setEndDate: function(endDate)
18863 this.endDate = endDate || Infinity;
18864 if (this.endDate !== Infinity) {
18865 this.endDate = this.parseDate(this.endDate);
18868 this.updateNavArrows();
18871 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18873 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18874 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18875 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18877 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18878 return parseInt(d, 10);
18881 this.updateNavArrows();
18884 updateNavArrows: function()
18886 if(this.singleMode){
18890 var d = new Date(this.viewDate),
18891 year = d.getUTCFullYear(),
18892 month = d.getUTCMonth();
18894 Roo.each(this.picker().select('.prev', true).elements, function(v){
18896 switch (this.viewMode) {
18899 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18905 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18912 Roo.each(this.picker().select('.next', true).elements, function(v){
18914 switch (this.viewMode) {
18917 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18923 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18931 moveMonth: function(date, dir)
18936 var new_date = new Date(date.valueOf()),
18937 day = new_date.getUTCDate(),
18938 month = new_date.getUTCMonth(),
18939 mag = Math.abs(dir),
18941 dir = dir > 0 ? 1 : -1;
18944 // If going back one month, make sure month is not current month
18945 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18947 return new_date.getUTCMonth() == month;
18949 // If going forward one month, make sure month is as expected
18950 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18952 return new_date.getUTCMonth() != new_month;
18954 new_month = month + dir;
18955 new_date.setUTCMonth(new_month);
18956 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18957 if (new_month < 0 || new_month > 11) {
18958 new_month = (new_month + 12) % 12;
18961 // For magnitudes >1, move one month at a time...
18962 for (var i=0; i<mag; i++) {
18963 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18964 new_date = this.moveMonth(new_date, dir);
18966 // ...then reset the day, keeping it in the new month
18967 new_month = new_date.getUTCMonth();
18968 new_date.setUTCDate(day);
18970 return new_month != new_date.getUTCMonth();
18973 // Common date-resetting loop -- if date is beyond end of month, make it
18976 new_date.setUTCDate(--day);
18977 new_date.setUTCMonth(new_month);
18982 moveYear: function(date, dir)
18984 return this.moveMonth(date, dir*12);
18987 dateWithinRange: function(date)
18989 return date >= this.startDate && date <= this.endDate;
18995 this.picker().remove();
18998 validateValue : function(value)
19000 if(value.length < 1) {
19001 if(this.allowBlank){
19007 if(value.length < this.minLength){
19010 if(value.length > this.maxLength){
19014 var vt = Roo.form.VTypes;
19015 if(!vt[this.vtype](value, this)){
19019 if(typeof this.validator == "function"){
19020 var msg = this.validator(value);
19026 if(this.regex && !this.regex.test(value)){
19030 if(typeof(this.parseDate(value)) == 'undefined'){
19034 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19038 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19048 Roo.apply(Roo.bootstrap.DateField, {
19059 html: '<i class="fa fa-arrow-left"/>'
19069 html: '<i class="fa fa-arrow-right"/>'
19111 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19112 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19113 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19114 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19115 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19128 navFnc: 'FullYear',
19133 navFnc: 'FullYear',
19138 Roo.apply(Roo.bootstrap.DateField, {
19142 cls: 'datepicker dropdown-menu roo-dynamic',
19146 cls: 'datepicker-days',
19150 cls: 'table-condensed',
19152 Roo.bootstrap.DateField.head,
19156 Roo.bootstrap.DateField.footer
19163 cls: 'datepicker-months',
19167 cls: 'table-condensed',
19169 Roo.bootstrap.DateField.head,
19170 Roo.bootstrap.DateField.content,
19171 Roo.bootstrap.DateField.footer
19178 cls: 'datepicker-years',
19182 cls: 'table-condensed',
19184 Roo.bootstrap.DateField.head,
19185 Roo.bootstrap.DateField.content,
19186 Roo.bootstrap.DateField.footer
19205 * @class Roo.bootstrap.TimeField
19206 * @extends Roo.bootstrap.Input
19207 * Bootstrap DateField class
19211 * Create a new TimeField
19212 * @param {Object} config The config object
19215 Roo.bootstrap.TimeField = function(config){
19216 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19220 * Fires when this field show.
19221 * @param {Roo.bootstrap.DateField} thisthis
19222 * @param {Mixed} date The date value
19227 * Fires when this field hide.
19228 * @param {Roo.bootstrap.DateField} this
19229 * @param {Mixed} date The date value
19234 * Fires when select a date.
19235 * @param {Roo.bootstrap.DateField} this
19236 * @param {Mixed} date The date value
19242 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19245 * @cfg {String} format
19246 * The default time format string which can be overriden for localization support. The format must be
19247 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19251 onRender: function(ct, position)
19254 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19256 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19258 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19260 this.pop = this.picker().select('>.datepicker-time',true).first();
19261 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19263 this.picker().on('mousedown', this.onMousedown, this);
19264 this.picker().on('click', this.onClick, this);
19266 this.picker().addClass('datepicker-dropdown');
19271 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19272 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19273 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19274 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19275 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19276 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19280 fireKey: function(e){
19281 if (!this.picker().isVisible()){
19282 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19288 e.preventDefault();
19296 this.onTogglePeriod();
19299 this.onIncrementMinutes();
19302 this.onDecrementMinutes();
19311 onClick: function(e) {
19312 e.stopPropagation();
19313 e.preventDefault();
19316 picker : function()
19318 return this.el.select('.datepicker', true).first();
19321 fillTime: function()
19323 var time = this.pop.select('tbody', true).first();
19325 time.dom.innerHTML = '';
19340 cls: 'hours-up glyphicon glyphicon-chevron-up'
19360 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19381 cls: 'timepicker-hour',
19396 cls: 'timepicker-minute',
19411 cls: 'btn btn-primary period',
19433 cls: 'hours-down glyphicon glyphicon-chevron-down'
19453 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19471 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19478 var hours = this.time.getHours();
19479 var minutes = this.time.getMinutes();
19492 hours = hours - 12;
19496 hours = '0' + hours;
19500 minutes = '0' + minutes;
19503 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19504 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19505 this.pop.select('button', true).first().dom.innerHTML = period;
19511 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19513 var cls = ['bottom'];
19515 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19522 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19527 this.picker().addClass(cls.join('-'));
19531 Roo.each(cls, function(c){
19533 _this.picker().setTop(_this.inputEl().getHeight());
19537 _this.picker().setTop(0 - _this.picker().getHeight());
19542 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19546 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19553 onFocus : function()
19555 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19559 onBlur : function()
19561 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19567 this.picker().show();
19572 this.fireEvent('show', this, this.date);
19577 this.picker().hide();
19580 this.fireEvent('hide', this, this.date);
19583 setTime : function()
19586 this.setValue(this.time.format(this.format));
19588 this.fireEvent('select', this, this.date);
19593 onMousedown: function(e){
19594 e.stopPropagation();
19595 e.preventDefault();
19598 onIncrementHours: function()
19600 Roo.log('onIncrementHours');
19601 this.time = this.time.add(Date.HOUR, 1);
19606 onDecrementHours: function()
19608 Roo.log('onDecrementHours');
19609 this.time = this.time.add(Date.HOUR, -1);
19613 onIncrementMinutes: function()
19615 Roo.log('onIncrementMinutes');
19616 this.time = this.time.add(Date.MINUTE, 1);
19620 onDecrementMinutes: function()
19622 Roo.log('onDecrementMinutes');
19623 this.time = this.time.add(Date.MINUTE, -1);
19627 onTogglePeriod: function()
19629 Roo.log('onTogglePeriod');
19630 this.time = this.time.add(Date.HOUR, 12);
19637 Roo.apply(Roo.bootstrap.TimeField, {
19667 cls: 'btn btn-info ok',
19679 Roo.apply(Roo.bootstrap.TimeField, {
19683 cls: 'datepicker dropdown-menu',
19687 cls: 'datepicker-time',
19691 cls: 'table-condensed',
19693 Roo.bootstrap.TimeField.content,
19694 Roo.bootstrap.TimeField.footer
19713 * @class Roo.bootstrap.MonthField
19714 * @extends Roo.bootstrap.Input
19715 * Bootstrap MonthField class
19717 * @cfg {String} language default en
19720 * Create a new MonthField
19721 * @param {Object} config The config object
19724 Roo.bootstrap.MonthField = function(config){
19725 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19730 * Fires when this field show.
19731 * @param {Roo.bootstrap.MonthField} this
19732 * @param {Mixed} date The date value
19737 * Fires when this field hide.
19738 * @param {Roo.bootstrap.MonthField} this
19739 * @param {Mixed} date The date value
19744 * Fires when select a date.
19745 * @param {Roo.bootstrap.MonthField} this
19746 * @param {String} oldvalue The old value
19747 * @param {String} newvalue The new value
19753 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19755 onRender: function(ct, position)
19758 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19760 this.language = this.language || 'en';
19761 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19762 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19764 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19765 this.isInline = false;
19766 this.isInput = true;
19767 this.component = this.el.select('.add-on', true).first() || false;
19768 this.component = (this.component && this.component.length === 0) ? false : this.component;
19769 this.hasInput = this.component && this.inputEL().length;
19771 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19773 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19775 this.picker().on('mousedown', this.onMousedown, this);
19776 this.picker().on('click', this.onClick, this);
19778 this.picker().addClass('datepicker-dropdown');
19780 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19781 v.setStyle('width', '189px');
19788 if(this.isInline) {
19794 setValue: function(v, suppressEvent)
19796 var o = this.getValue();
19798 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19802 if(suppressEvent !== true){
19803 this.fireEvent('select', this, o, v);
19808 getValue: function()
19813 onClick: function(e)
19815 e.stopPropagation();
19816 e.preventDefault();
19818 var target = e.getTarget();
19820 if(target.nodeName.toLowerCase() === 'i'){
19821 target = Roo.get(target).dom.parentNode;
19824 var nodeName = target.nodeName;
19825 var className = target.className;
19826 var html = target.innerHTML;
19828 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19832 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19834 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19840 picker : function()
19842 return this.pickerEl;
19845 fillMonths: function()
19848 var months = this.picker().select('>.datepicker-months td', true).first();
19850 months.dom.innerHTML = '';
19856 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19859 months.createChild(month);
19868 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19869 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19872 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19873 e.removeClass('active');
19875 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19876 e.addClass('active');
19883 if(this.isInline) {
19887 this.picker().removeClass(['bottom', 'top']);
19889 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19891 * place to the top of element!
19895 this.picker().addClass('top');
19896 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19901 this.picker().addClass('bottom');
19903 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19906 onFocus : function()
19908 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19912 onBlur : function()
19914 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19916 var d = this.inputEl().getValue();
19925 this.picker().show();
19926 this.picker().select('>.datepicker-months', true).first().show();
19930 this.fireEvent('show', this, this.date);
19935 if(this.isInline) {
19938 this.picker().hide();
19939 this.fireEvent('hide', this, this.date);
19943 onMousedown: function(e)
19945 e.stopPropagation();
19946 e.preventDefault();
19951 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19955 fireKey: function(e)
19957 if (!this.picker().isVisible()){
19958 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19969 e.preventDefault();
19973 dir = e.keyCode == 37 ? -1 : 1;
19975 this.vIndex = this.vIndex + dir;
19977 if(this.vIndex < 0){
19981 if(this.vIndex > 11){
19985 if(isNaN(this.vIndex)){
19989 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19995 dir = e.keyCode == 38 ? -1 : 1;
19997 this.vIndex = this.vIndex + dir * 4;
19999 if(this.vIndex < 0){
20003 if(this.vIndex > 11){
20007 if(isNaN(this.vIndex)){
20011 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20016 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20017 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20021 e.preventDefault();
20024 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20025 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20041 this.picker().remove();
20046 Roo.apply(Roo.bootstrap.MonthField, {
20065 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20066 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20071 Roo.apply(Roo.bootstrap.MonthField, {
20075 cls: 'datepicker dropdown-menu roo-dynamic',
20079 cls: 'datepicker-months',
20083 cls: 'table-condensed',
20085 Roo.bootstrap.DateField.content
20105 * @class Roo.bootstrap.CheckBox
20106 * @extends Roo.bootstrap.Input
20107 * Bootstrap CheckBox class
20109 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20110 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20111 * @cfg {String} boxLabel The text that appears beside the checkbox
20112 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20113 * @cfg {Boolean} checked initnal the element
20114 * @cfg {Boolean} inline inline the element (default false)
20115 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20118 * Create a new CheckBox
20119 * @param {Object} config The config object
20122 Roo.bootstrap.CheckBox = function(config){
20123 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20128 * Fires when the element is checked or unchecked.
20129 * @param {Roo.bootstrap.CheckBox} this This input
20130 * @param {Boolean} checked The new checked value
20137 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20139 inputType: 'checkbox',
20147 getAutoCreate : function()
20149 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20155 cfg.cls = 'form-group ' + this.inputType; //input-group
20158 cfg.cls += ' ' + this.inputType + '-inline';
20164 type : this.inputType,
20165 value : this.inputValue,
20166 cls : 'roo-' + this.inputType, //'form-box',
20167 placeholder : this.placeholder || ''
20171 if(this.inputType != 'radio'){
20175 cls : 'roo-hidden-value',
20176 value : this.checked ? this.valueOff : this.inputValue
20181 if (this.weight) { // Validity check?
20182 cfg.cls += " " + this.inputType + "-" + this.weight;
20185 if (this.disabled) {
20186 input.disabled=true;
20190 input.checked = this.checked;
20197 input.name = this.name;
20199 if(this.inputType != 'radio'){
20200 hidden.name = this.name;
20201 input.name = '_hidden_' + this.name;
20206 input.cls += ' input-' + this.size;
20211 ['xs','sm','md','lg'].map(function(size){
20212 if (settings[size]) {
20213 cfg.cls += ' col-' + size + '-' + settings[size];
20217 var inputblock = input;
20219 if (this.before || this.after) {
20222 cls : 'input-group',
20227 inputblock.cn.push({
20229 cls : 'input-group-addon',
20234 inputblock.cn.push(input);
20236 if(this.inputType != 'radio'){
20237 inputblock.cn.push(hidden);
20241 inputblock.cn.push({
20243 cls : 'input-group-addon',
20250 if (align ==='left' && this.fieldLabel.length) {
20251 // Roo.log("left and has label");
20256 cls : 'control-label',
20257 html : this.fieldLabel
20268 if(this.labelWidth > 12){
20269 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20272 if(this.labelWidth < 13 && this.labelmd == 0){
20273 this.labelmd = this.labelWidth;
20276 if(this.labellg > 0){
20277 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20278 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20281 if(this.labelmd > 0){
20282 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20283 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20286 if(this.labelsm > 0){
20287 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20288 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20291 if(this.labelxs > 0){
20292 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20293 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20296 } else if ( this.fieldLabel.length) {
20297 // Roo.log(" label");
20301 tag: this.boxLabel ? 'span' : 'label',
20303 cls: 'control-label box-input-label',
20304 //cls : 'input-group-addon',
20305 html : this.fieldLabel
20315 // Roo.log(" no label && no align");
20316 cfg.cn = [ inputblock ] ;
20322 var boxLabelCfg = {
20324 //'for': id, // box label is handled by onclick - so no for...
20326 html: this.boxLabel
20330 boxLabelCfg.tooltip = this.tooltip;
20333 cfg.cn.push(boxLabelCfg);
20336 if(this.inputType != 'radio'){
20337 cfg.cn.push(hidden);
20345 * return the real input element.
20347 inputEl: function ()
20349 return this.el.select('input.roo-' + this.inputType,true).first();
20351 hiddenEl: function ()
20353 return this.el.select('input.roo-hidden-value',true).first();
20356 labelEl: function()
20358 return this.el.select('label.control-label',true).first();
20360 /* depricated... */
20364 return this.labelEl();
20367 boxLabelEl: function()
20369 return this.el.select('label.box-label',true).first();
20372 initEvents : function()
20374 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20376 this.inputEl().on('click', this.onClick, this);
20378 if (this.boxLabel) {
20379 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20382 this.startValue = this.getValue();
20385 Roo.bootstrap.CheckBox.register(this);
20389 onClick : function()
20391 this.setChecked(!this.checked);
20394 setChecked : function(state,suppressEvent)
20396 this.startValue = this.getValue();
20398 if(this.inputType == 'radio'){
20400 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20401 e.dom.checked = false;
20404 this.inputEl().dom.checked = true;
20406 this.inputEl().dom.value = this.inputValue;
20408 if(suppressEvent !== true){
20409 this.fireEvent('check', this, true);
20417 this.checked = state;
20419 this.inputEl().dom.checked = state;
20422 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20424 if(suppressEvent !== true){
20425 this.fireEvent('check', this, state);
20431 getValue : function()
20433 if(this.inputType == 'radio'){
20434 return this.getGroupValue();
20437 return this.hiddenEl().dom.value;
20441 getGroupValue : function()
20443 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20447 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20450 setValue : function(v,suppressEvent)
20452 if(this.inputType == 'radio'){
20453 this.setGroupValue(v, suppressEvent);
20457 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20462 setGroupValue : function(v, suppressEvent)
20464 this.startValue = this.getValue();
20466 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20467 e.dom.checked = false;
20469 if(e.dom.value == v){
20470 e.dom.checked = true;
20474 if(suppressEvent !== true){
20475 this.fireEvent('check', this, true);
20483 validate : function()
20487 (this.inputType == 'radio' && this.validateRadio()) ||
20488 (this.inputType == 'checkbox' && this.validateCheckbox())
20494 this.markInvalid();
20498 validateRadio : function()
20500 if(this.allowBlank){
20506 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20507 if(!e.dom.checked){
20519 validateCheckbox : function()
20522 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20523 //return (this.getValue() == this.inputValue) ? true : false;
20526 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20534 for(var i in group){
20539 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20546 * Mark this field as valid
20548 markValid : function()
20552 this.fireEvent('valid', this);
20554 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20557 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20564 if(this.inputType == 'radio'){
20565 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20566 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20567 e.findParent('.form-group', false, true).addClass(_this.validClass);
20574 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20575 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20579 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20585 for(var i in group){
20586 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20587 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20592 * Mark this field as invalid
20593 * @param {String} msg The validation message
20595 markInvalid : function(msg)
20597 if(this.allowBlank){
20603 this.fireEvent('invalid', this, msg);
20605 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20608 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20612 label.markInvalid();
20615 if(this.inputType == 'radio'){
20616 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20617 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20618 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20625 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20626 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20630 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20636 for(var i in group){
20637 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20638 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20643 clearInvalid : function()
20645 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20647 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20649 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20652 label.iconEl.removeClass(label.validClass);
20653 label.iconEl.removeClass(label.invalidClass);
20657 disable : function()
20659 if(this.inputType != 'radio'){
20660 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20667 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20668 _this.getActionEl().addClass(this.disabledClass);
20669 e.dom.disabled = true;
20673 this.disabled = true;
20674 this.fireEvent("disable", this);
20678 enable : function()
20680 if(this.inputType != 'radio'){
20681 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20688 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20689 _this.getActionEl().removeClass(this.disabledClass);
20690 e.dom.disabled = false;
20694 this.disabled = false;
20695 this.fireEvent("enable", this);
20701 Roo.apply(Roo.bootstrap.CheckBox, {
20706 * register a CheckBox Group
20707 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20709 register : function(checkbox)
20711 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20712 this.groups[checkbox.groupId] = {};
20715 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20719 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20723 * fetch a CheckBox Group based on the group ID
20724 * @param {string} the group ID
20725 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20727 get: function(groupId) {
20728 if (typeof(this.groups[groupId]) == 'undefined') {
20732 return this.groups[groupId] ;
20745 * @class Roo.bootstrap.Radio
20746 * @extends Roo.bootstrap.Component
20747 * Bootstrap Radio class
20748 * @cfg {String} boxLabel - the label associated
20749 * @cfg {String} value - the value of radio
20752 * Create a new Radio
20753 * @param {Object} config The config object
20755 Roo.bootstrap.Radio = function(config){
20756 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20760 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20766 getAutoCreate : function()
20770 cls : 'form-group radio',
20775 html : this.boxLabel
20783 initEvents : function()
20785 this.parent().register(this);
20787 this.el.on('click', this.onClick, this);
20791 onClick : function()
20793 this.setChecked(true);
20796 setChecked : function(state, suppressEvent)
20798 this.parent().setValue(this.value, suppressEvent);
20802 setBoxLabel : function(v)
20807 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20822 * @class Roo.bootstrap.SecurePass
20823 * @extends Roo.bootstrap.Input
20824 * Bootstrap SecurePass class
20828 * Create a new SecurePass
20829 * @param {Object} config The config object
20832 Roo.bootstrap.SecurePass = function (config) {
20833 // these go here, so the translation tool can replace them..
20835 PwdEmpty: "Please type a password, and then retype it to confirm.",
20836 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20837 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20838 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20839 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20840 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20841 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20842 TooWeak: "Your password is Too Weak."
20844 this.meterLabel = "Password strength:";
20845 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20846 this.meterClass = [
20847 "roo-password-meter-tooweak",
20848 "roo-password-meter-weak",
20849 "roo-password-meter-medium",
20850 "roo-password-meter-strong",
20851 "roo-password-meter-grey"
20856 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20859 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20861 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20863 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20864 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20865 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20866 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20867 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20868 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20869 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20879 * @cfg {String/Object} Label for the strength meter (defaults to
20880 * 'Password strength:')
20885 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20886 * ['Weak', 'Medium', 'Strong'])
20889 pwdStrengths: false,
20902 initEvents: function ()
20904 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20906 if (this.el.is('input[type=password]') && Roo.isSafari) {
20907 this.el.on('keydown', this.SafariOnKeyDown, this);
20910 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20913 onRender: function (ct, position)
20915 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20916 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20917 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20919 this.trigger.createChild({
20924 cls: 'roo-password-meter-grey col-xs-12',
20927 //width: this.meterWidth + 'px'
20931 cls: 'roo-password-meter-text'
20937 if (this.hideTrigger) {
20938 this.trigger.setDisplayed(false);
20940 this.setSize(this.width || '', this.height || '');
20943 onDestroy: function ()
20945 if (this.trigger) {
20946 this.trigger.removeAllListeners();
20947 this.trigger.remove();
20950 this.wrap.remove();
20952 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20955 checkStrength: function ()
20957 var pwd = this.inputEl().getValue();
20958 if (pwd == this._lastPwd) {
20963 if (this.ClientSideStrongPassword(pwd)) {
20965 } else if (this.ClientSideMediumPassword(pwd)) {
20967 } else if (this.ClientSideWeakPassword(pwd)) {
20973 Roo.log('strength1: ' + strength);
20975 //var pm = this.trigger.child('div/div/div').dom;
20976 var pm = this.trigger.child('div/div');
20977 pm.removeClass(this.meterClass);
20978 pm.addClass(this.meterClass[strength]);
20981 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20983 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20985 this._lastPwd = pwd;
20989 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20991 this._lastPwd = '';
20993 var pm = this.trigger.child('div/div');
20994 pm.removeClass(this.meterClass);
20995 pm.addClass('roo-password-meter-grey');
20998 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21001 this.inputEl().dom.type='password';
21004 validateValue: function (value)
21007 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21010 if (value.length == 0) {
21011 if (this.allowBlank) {
21012 this.clearInvalid();
21016 this.markInvalid(this.errors.PwdEmpty);
21017 this.errorMsg = this.errors.PwdEmpty;
21025 if ('[\x21-\x7e]*'.match(value)) {
21026 this.markInvalid(this.errors.PwdBadChar);
21027 this.errorMsg = this.errors.PwdBadChar;
21030 if (value.length < 6) {
21031 this.markInvalid(this.errors.PwdShort);
21032 this.errorMsg = this.errors.PwdShort;
21035 if (value.length > 16) {
21036 this.markInvalid(this.errors.PwdLong);
21037 this.errorMsg = this.errors.PwdLong;
21041 if (this.ClientSideStrongPassword(value)) {
21043 } else if (this.ClientSideMediumPassword(value)) {
21045 } else if (this.ClientSideWeakPassword(value)) {
21052 if (strength < 2) {
21053 //this.markInvalid(this.errors.TooWeak);
21054 this.errorMsg = this.errors.TooWeak;
21059 console.log('strength2: ' + strength);
21061 //var pm = this.trigger.child('div/div/div').dom;
21063 var pm = this.trigger.child('div/div');
21064 pm.removeClass(this.meterClass);
21065 pm.addClass(this.meterClass[strength]);
21067 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21069 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21071 this.errorMsg = '';
21075 CharacterSetChecks: function (type)
21078 this.fResult = false;
21081 isctype: function (character, type)
21084 case this.kCapitalLetter:
21085 if (character >= 'A' && character <= 'Z') {
21090 case this.kSmallLetter:
21091 if (character >= 'a' && character <= 'z') {
21097 if (character >= '0' && character <= '9') {
21102 case this.kPunctuation:
21103 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21114 IsLongEnough: function (pwd, size)
21116 return !(pwd == null || isNaN(size) || pwd.length < size);
21119 SpansEnoughCharacterSets: function (word, nb)
21121 if (!this.IsLongEnough(word, nb))
21126 var characterSetChecks = new Array(
21127 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21128 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21131 for (var index = 0; index < word.length; ++index) {
21132 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21133 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21134 characterSetChecks[nCharSet].fResult = true;
21141 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21142 if (characterSetChecks[nCharSet].fResult) {
21147 if (nCharSets < nb) {
21153 ClientSideStrongPassword: function (pwd)
21155 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21158 ClientSideMediumPassword: function (pwd)
21160 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21163 ClientSideWeakPassword: function (pwd)
21165 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21168 })//<script type="text/javascript">
21171 * Based Ext JS Library 1.1.1
21172 * Copyright(c) 2006-2007, Ext JS, LLC.
21178 * @class Roo.HtmlEditorCore
21179 * @extends Roo.Component
21180 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21182 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21185 Roo.HtmlEditorCore = function(config){
21188 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21193 * @event initialize
21194 * Fires when the editor is fully initialized (including the iframe)
21195 * @param {Roo.HtmlEditorCore} this
21200 * Fires when the editor is first receives the focus. Any insertion must wait
21201 * until after this event.
21202 * @param {Roo.HtmlEditorCore} this
21206 * @event beforesync
21207 * Fires before the textarea is updated with content from the editor iframe. Return false
21208 * to cancel the sync.
21209 * @param {Roo.HtmlEditorCore} this
21210 * @param {String} html
21214 * @event beforepush
21215 * Fires before the iframe editor is updated with content from the textarea. Return false
21216 * to cancel the push.
21217 * @param {Roo.HtmlEditorCore} this
21218 * @param {String} html
21223 * Fires when the textarea is updated with content from the editor iframe.
21224 * @param {Roo.HtmlEditorCore} this
21225 * @param {String} html
21230 * Fires when the iframe editor is updated with content from the textarea.
21231 * @param {Roo.HtmlEditorCore} this
21232 * @param {String} html
21237 * @event editorevent
21238 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21239 * @param {Roo.HtmlEditorCore} this
21245 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21247 // defaults : white / black...
21248 this.applyBlacklists();
21255 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21259 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21265 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21270 * @cfg {Number} height (in pixels)
21274 * @cfg {Number} width (in pixels)
21279 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21282 stylesheets: false,
21287 // private properties
21288 validationEvent : false,
21290 initialized : false,
21292 sourceEditMode : false,
21293 onFocus : Roo.emptyFn,
21295 hideMode:'offsets',
21299 // blacklist + whitelisted elements..
21306 * Protected method that will not generally be called directly. It
21307 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21308 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21310 getDocMarkup : function(){
21314 // inherit styels from page...??
21315 if (this.stylesheets === false) {
21317 Roo.get(document.head).select('style').each(function(node) {
21318 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21321 Roo.get(document.head).select('link').each(function(node) {
21322 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21325 } else if (!this.stylesheets.length) {
21327 st = '<style type="text/css">' +
21328 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21331 st = '<style type="text/css">' +
21336 st += '<style type="text/css">' +
21337 'IMG { cursor: pointer } ' +
21340 var cls = 'roo-htmleditor-body';
21342 if(this.bodyCls.length){
21343 cls += ' ' + this.bodyCls;
21346 return '<html><head>' + st +
21347 //<style type="text/css">' +
21348 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21350 ' </head><body class="' + cls + '"></body></html>';
21354 onRender : function(ct, position)
21357 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21358 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21361 this.el.dom.style.border = '0 none';
21362 this.el.dom.setAttribute('tabIndex', -1);
21363 this.el.addClass('x-hidden hide');
21367 if(Roo.isIE){ // fix IE 1px bogus margin
21368 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21372 this.frameId = Roo.id();
21376 var iframe = this.owner.wrap.createChild({
21378 cls: 'form-control', // bootstrap..
21380 name: this.frameId,
21381 frameBorder : 'no',
21382 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21387 this.iframe = iframe.dom;
21389 this.assignDocWin();
21391 this.doc.designMode = 'on';
21394 this.doc.write(this.getDocMarkup());
21398 var task = { // must defer to wait for browser to be ready
21400 //console.log("run task?" + this.doc.readyState);
21401 this.assignDocWin();
21402 if(this.doc.body || this.doc.readyState == 'complete'){
21404 this.doc.designMode="on";
21408 Roo.TaskMgr.stop(task);
21409 this.initEditor.defer(10, this);
21416 Roo.TaskMgr.start(task);
21421 onResize : function(w, h)
21423 Roo.log('resize: ' +w + ',' + h );
21424 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21428 if(typeof w == 'number'){
21430 this.iframe.style.width = w + 'px';
21432 if(typeof h == 'number'){
21434 this.iframe.style.height = h + 'px';
21436 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21443 * Toggles the editor between standard and source edit mode.
21444 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21446 toggleSourceEdit : function(sourceEditMode){
21448 this.sourceEditMode = sourceEditMode === true;
21450 if(this.sourceEditMode){
21452 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21455 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21456 //this.iframe.className = '';
21459 //this.setSize(this.owner.wrap.getSize());
21460 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21467 * Protected method that will not generally be called directly. If you need/want
21468 * custom HTML cleanup, this is the method you should override.
21469 * @param {String} html The HTML to be cleaned
21470 * return {String} The cleaned HTML
21472 cleanHtml : function(html){
21473 html = String(html);
21474 if(html.length > 5){
21475 if(Roo.isSafari){ // strip safari nonsense
21476 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21479 if(html == ' '){
21486 * HTML Editor -> Textarea
21487 * Protected method that will not generally be called directly. Syncs the contents
21488 * of the editor iframe with the textarea.
21490 syncValue : function(){
21491 if(this.initialized){
21492 var bd = (this.doc.body || this.doc.documentElement);
21493 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21494 var html = bd.innerHTML;
21496 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21497 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21499 html = '<div style="'+m[0]+'">' + html + '</div>';
21502 html = this.cleanHtml(html);
21503 // fix up the special chars.. normaly like back quotes in word...
21504 // however we do not want to do this with chinese..
21505 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21506 var cc = b.charCodeAt();
21508 (cc >= 0x4E00 && cc < 0xA000 ) ||
21509 (cc >= 0x3400 && cc < 0x4E00 ) ||
21510 (cc >= 0xf900 && cc < 0xfb00 )
21516 if(this.owner.fireEvent('beforesync', this, html) !== false){
21517 this.el.dom.value = html;
21518 this.owner.fireEvent('sync', this, html);
21524 * Protected method that will not generally be called directly. Pushes the value of the textarea
21525 * into the iframe editor.
21527 pushValue : function(){
21528 if(this.initialized){
21529 var v = this.el.dom.value.trim();
21531 // if(v.length < 1){
21535 if(this.owner.fireEvent('beforepush', this, v) !== false){
21536 var d = (this.doc.body || this.doc.documentElement);
21538 this.cleanUpPaste();
21539 this.el.dom.value = d.innerHTML;
21540 this.owner.fireEvent('push', this, v);
21546 deferFocus : function(){
21547 this.focus.defer(10, this);
21551 focus : function(){
21552 if(this.win && !this.sourceEditMode){
21559 assignDocWin: function()
21561 var iframe = this.iframe;
21564 this.doc = iframe.contentWindow.document;
21565 this.win = iframe.contentWindow;
21567 // if (!Roo.get(this.frameId)) {
21570 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21571 // this.win = Roo.get(this.frameId).dom.contentWindow;
21573 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21577 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21578 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21583 initEditor : function(){
21584 //console.log("INIT EDITOR");
21585 this.assignDocWin();
21589 this.doc.designMode="on";
21591 this.doc.write(this.getDocMarkup());
21594 var dbody = (this.doc.body || this.doc.documentElement);
21595 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21596 // this copies styles from the containing element into thsi one..
21597 // not sure why we need all of this..
21598 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21600 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21601 //ss['background-attachment'] = 'fixed'; // w3c
21602 dbody.bgProperties = 'fixed'; // ie
21603 //Roo.DomHelper.applyStyles(dbody, ss);
21604 Roo.EventManager.on(this.doc, {
21605 //'mousedown': this.onEditorEvent,
21606 'mouseup': this.onEditorEvent,
21607 'dblclick': this.onEditorEvent,
21608 'click': this.onEditorEvent,
21609 'keyup': this.onEditorEvent,
21614 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21616 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21617 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21619 this.initialized = true;
21621 this.owner.fireEvent('initialize', this);
21626 onDestroy : function(){
21632 //for (var i =0; i < this.toolbars.length;i++) {
21633 // // fixme - ask toolbars for heights?
21634 // this.toolbars[i].onDestroy();
21637 //this.wrap.dom.innerHTML = '';
21638 //this.wrap.remove();
21643 onFirstFocus : function(){
21645 this.assignDocWin();
21648 this.activated = true;
21651 if(Roo.isGecko){ // prevent silly gecko errors
21653 var s = this.win.getSelection();
21654 if(!s.focusNode || s.focusNode.nodeType != 3){
21655 var r = s.getRangeAt(0);
21656 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21661 this.execCmd('useCSS', true);
21662 this.execCmd('styleWithCSS', false);
21665 this.owner.fireEvent('activate', this);
21669 adjustFont: function(btn){
21670 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21671 //if(Roo.isSafari){ // safari
21674 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21675 if(Roo.isSafari){ // safari
21676 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21677 v = (v < 10) ? 10 : v;
21678 v = (v > 48) ? 48 : v;
21679 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21684 v = Math.max(1, v+adjust);
21686 this.execCmd('FontSize', v );
21689 onEditorEvent : function(e)
21691 this.owner.fireEvent('editorevent', this, e);
21692 // this.updateToolbar();
21693 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21696 insertTag : function(tg)
21698 // could be a bit smarter... -> wrap the current selected tRoo..
21699 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21701 range = this.createRange(this.getSelection());
21702 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21703 wrappingNode.appendChild(range.extractContents());
21704 range.insertNode(wrappingNode);
21711 this.execCmd("formatblock", tg);
21715 insertText : function(txt)
21719 var range = this.createRange();
21720 range.deleteContents();
21721 //alert(Sender.getAttribute('label'));
21723 range.insertNode(this.doc.createTextNode(txt));
21729 * Executes a Midas editor command on the editor document and performs necessary focus and
21730 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21731 * @param {String} cmd The Midas command
21732 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21734 relayCmd : function(cmd, value){
21736 this.execCmd(cmd, value);
21737 this.owner.fireEvent('editorevent', this);
21738 //this.updateToolbar();
21739 this.owner.deferFocus();
21743 * Executes a Midas editor command directly on the editor document.
21744 * For visual commands, you should use {@link #relayCmd} instead.
21745 * <b>This should only be called after the editor is initialized.</b>
21746 * @param {String} cmd The Midas command
21747 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21749 execCmd : function(cmd, value){
21750 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21757 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21759 * @param {String} text | dom node..
21761 insertAtCursor : function(text)
21764 if(!this.activated){
21770 var r = this.doc.selection.createRange();
21781 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21785 // from jquery ui (MIT licenced)
21787 var win = this.win;
21789 if (win.getSelection && win.getSelection().getRangeAt) {
21790 range = win.getSelection().getRangeAt(0);
21791 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21792 range.insertNode(node);
21793 } else if (win.document.selection && win.document.selection.createRange) {
21794 // no firefox support
21795 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21796 win.document.selection.createRange().pasteHTML(txt);
21798 // no firefox support
21799 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21800 this.execCmd('InsertHTML', txt);
21809 mozKeyPress : function(e){
21811 var c = e.getCharCode(), cmd;
21814 c = String.fromCharCode(c).toLowerCase();
21828 this.cleanUpPaste.defer(100, this);
21836 e.preventDefault();
21844 fixKeys : function(){ // load time branching for fastest keydown performance
21846 return function(e){
21847 var k = e.getKey(), r;
21850 r = this.doc.selection.createRange();
21853 r.pasteHTML('    ');
21860 r = this.doc.selection.createRange();
21862 var target = r.parentElement();
21863 if(!target || target.tagName.toLowerCase() != 'li'){
21865 r.pasteHTML('<br />');
21871 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21872 this.cleanUpPaste.defer(100, this);
21878 }else if(Roo.isOpera){
21879 return function(e){
21880 var k = e.getKey();
21884 this.execCmd('InsertHTML','    ');
21887 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21888 this.cleanUpPaste.defer(100, this);
21893 }else if(Roo.isSafari){
21894 return function(e){
21895 var k = e.getKey();
21899 this.execCmd('InsertText','\t');
21903 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21904 this.cleanUpPaste.defer(100, this);
21912 getAllAncestors: function()
21914 var p = this.getSelectedNode();
21917 a.push(p); // push blank onto stack..
21918 p = this.getParentElement();
21922 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21926 a.push(this.doc.body);
21930 lastSelNode : false,
21933 getSelection : function()
21935 this.assignDocWin();
21936 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21939 getSelectedNode: function()
21941 // this may only work on Gecko!!!
21943 // should we cache this!!!!
21948 var range = this.createRange(this.getSelection()).cloneRange();
21951 var parent = range.parentElement();
21953 var testRange = range.duplicate();
21954 testRange.moveToElementText(parent);
21955 if (testRange.inRange(range)) {
21958 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21961 parent = parent.parentElement;
21966 // is ancestor a text element.
21967 var ac = range.commonAncestorContainer;
21968 if (ac.nodeType == 3) {
21969 ac = ac.parentNode;
21972 var ar = ac.childNodes;
21975 var other_nodes = [];
21976 var has_other_nodes = false;
21977 for (var i=0;i<ar.length;i++) {
21978 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21981 // fullly contained node.
21983 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21988 // probably selected..
21989 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21990 other_nodes.push(ar[i]);
21994 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21999 has_other_nodes = true;
22001 if (!nodes.length && other_nodes.length) {
22002 nodes= other_nodes;
22004 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22010 createRange: function(sel)
22012 // this has strange effects when using with
22013 // top toolbar - not sure if it's a great idea.
22014 //this.editor.contentWindow.focus();
22015 if (typeof sel != "undefined") {
22017 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22019 return this.doc.createRange();
22022 return this.doc.createRange();
22025 getParentElement: function()
22028 this.assignDocWin();
22029 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22031 var range = this.createRange(sel);
22034 var p = range.commonAncestorContainer;
22035 while (p.nodeType == 3) { // text node
22046 * Range intersection.. the hard stuff...
22050 * [ -- selected range --- ]
22054 * if end is before start or hits it. fail.
22055 * if start is after end or hits it fail.
22057 * if either hits (but other is outside. - then it's not
22063 // @see http://www.thismuchiknow.co.uk/?p=64.
22064 rangeIntersectsNode : function(range, node)
22066 var nodeRange = node.ownerDocument.createRange();
22068 nodeRange.selectNode(node);
22070 nodeRange.selectNodeContents(node);
22073 var rangeStartRange = range.cloneRange();
22074 rangeStartRange.collapse(true);
22076 var rangeEndRange = range.cloneRange();
22077 rangeEndRange.collapse(false);
22079 var nodeStartRange = nodeRange.cloneRange();
22080 nodeStartRange.collapse(true);
22082 var nodeEndRange = nodeRange.cloneRange();
22083 nodeEndRange.collapse(false);
22085 return rangeStartRange.compareBoundaryPoints(
22086 Range.START_TO_START, nodeEndRange) == -1 &&
22087 rangeEndRange.compareBoundaryPoints(
22088 Range.START_TO_START, nodeStartRange) == 1;
22092 rangeCompareNode : function(range, node)
22094 var nodeRange = node.ownerDocument.createRange();
22096 nodeRange.selectNode(node);
22098 nodeRange.selectNodeContents(node);
22102 range.collapse(true);
22104 nodeRange.collapse(true);
22106 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22107 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22109 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22111 var nodeIsBefore = ss == 1;
22112 var nodeIsAfter = ee == -1;
22114 if (nodeIsBefore && nodeIsAfter) {
22117 if (!nodeIsBefore && nodeIsAfter) {
22118 return 1; //right trailed.
22121 if (nodeIsBefore && !nodeIsAfter) {
22122 return 2; // left trailed.
22128 // private? - in a new class?
22129 cleanUpPaste : function()
22131 // cleans up the whole document..
22132 Roo.log('cleanuppaste');
22134 this.cleanUpChildren(this.doc.body);
22135 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22136 if (clean != this.doc.body.innerHTML) {
22137 this.doc.body.innerHTML = clean;
22142 cleanWordChars : function(input) {// change the chars to hex code
22143 var he = Roo.HtmlEditorCore;
22145 var output = input;
22146 Roo.each(he.swapCodes, function(sw) {
22147 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22149 output = output.replace(swapper, sw[1]);
22156 cleanUpChildren : function (n)
22158 if (!n.childNodes.length) {
22161 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22162 this.cleanUpChild(n.childNodes[i]);
22169 cleanUpChild : function (node)
22172 //console.log(node);
22173 if (node.nodeName == "#text") {
22174 // clean up silly Windows -- stuff?
22177 if (node.nodeName == "#comment") {
22178 node.parentNode.removeChild(node);
22179 // clean up silly Windows -- stuff?
22182 var lcname = node.tagName.toLowerCase();
22183 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22184 // whitelist of tags..
22186 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22188 node.parentNode.removeChild(node);
22193 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22195 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22196 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22198 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22199 // remove_keep_children = true;
22202 if (remove_keep_children) {
22203 this.cleanUpChildren(node);
22204 // inserts everything just before this node...
22205 while (node.childNodes.length) {
22206 var cn = node.childNodes[0];
22207 node.removeChild(cn);
22208 node.parentNode.insertBefore(cn, node);
22210 node.parentNode.removeChild(node);
22214 if (!node.attributes || !node.attributes.length) {
22215 this.cleanUpChildren(node);
22219 function cleanAttr(n,v)
22222 if (v.match(/^\./) || v.match(/^\//)) {
22225 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22228 if (v.match(/^#/)) {
22231 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22232 node.removeAttribute(n);
22236 var cwhite = this.cwhite;
22237 var cblack = this.cblack;
22239 function cleanStyle(n,v)
22241 if (v.match(/expression/)) { //XSS?? should we even bother..
22242 node.removeAttribute(n);
22246 var parts = v.split(/;/);
22249 Roo.each(parts, function(p) {
22250 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22254 var l = p.split(':').shift().replace(/\s+/g,'');
22255 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22257 if ( cwhite.length && cblack.indexOf(l) > -1) {
22258 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22259 //node.removeAttribute(n);
22263 // only allow 'c whitelisted system attributes'
22264 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22265 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22266 //node.removeAttribute(n);
22276 if (clean.length) {
22277 node.setAttribute(n, clean.join(';'));
22279 node.removeAttribute(n);
22285 for (var i = node.attributes.length-1; i > -1 ; i--) {
22286 var a = node.attributes[i];
22289 if (a.name.toLowerCase().substr(0,2)=='on') {
22290 node.removeAttribute(a.name);
22293 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22294 node.removeAttribute(a.name);
22297 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22298 cleanAttr(a.name,a.value); // fixme..
22301 if (a.name == 'style') {
22302 cleanStyle(a.name,a.value);
22305 /// clean up MS crap..
22306 // tecnically this should be a list of valid class'es..
22309 if (a.name == 'class') {
22310 if (a.value.match(/^Mso/)) {
22311 node.className = '';
22314 if (a.value.match(/^body$/)) {
22315 node.className = '';
22326 this.cleanUpChildren(node);
22332 * Clean up MS wordisms...
22334 cleanWord : function(node)
22339 this.cleanWord(this.doc.body);
22342 if (node.nodeName == "#text") {
22343 // clean up silly Windows -- stuff?
22346 if (node.nodeName == "#comment") {
22347 node.parentNode.removeChild(node);
22348 // clean up silly Windows -- stuff?
22352 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22353 node.parentNode.removeChild(node);
22357 // remove - but keep children..
22358 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22359 while (node.childNodes.length) {
22360 var cn = node.childNodes[0];
22361 node.removeChild(cn);
22362 node.parentNode.insertBefore(cn, node);
22364 node.parentNode.removeChild(node);
22365 this.iterateChildren(node, this.cleanWord);
22369 if (node.className.length) {
22371 var cn = node.className.split(/\W+/);
22373 Roo.each(cn, function(cls) {
22374 if (cls.match(/Mso[a-zA-Z]+/)) {
22379 node.className = cna.length ? cna.join(' ') : '';
22381 node.removeAttribute("class");
22385 if (node.hasAttribute("lang")) {
22386 node.removeAttribute("lang");
22389 if (node.hasAttribute("style")) {
22391 var styles = node.getAttribute("style").split(";");
22393 Roo.each(styles, function(s) {
22394 if (!s.match(/:/)) {
22397 var kv = s.split(":");
22398 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22401 // what ever is left... we allow.
22404 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22405 if (!nstyle.length) {
22406 node.removeAttribute('style');
22409 this.iterateChildren(node, this.cleanWord);
22415 * iterateChildren of a Node, calling fn each time, using this as the scole..
22416 * @param {DomNode} node node to iterate children of.
22417 * @param {Function} fn method of this class to call on each item.
22419 iterateChildren : function(node, fn)
22421 if (!node.childNodes.length) {
22424 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22425 fn.call(this, node.childNodes[i])
22431 * cleanTableWidths.
22433 * Quite often pasting from word etc.. results in tables with column and widths.
22434 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22437 cleanTableWidths : function(node)
22442 this.cleanTableWidths(this.doc.body);
22447 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22450 Roo.log(node.tagName);
22451 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22452 this.iterateChildren(node, this.cleanTableWidths);
22455 if (node.hasAttribute('width')) {
22456 node.removeAttribute('width');
22460 if (node.hasAttribute("style")) {
22463 var styles = node.getAttribute("style").split(";");
22465 Roo.each(styles, function(s) {
22466 if (!s.match(/:/)) {
22469 var kv = s.split(":");
22470 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22473 // what ever is left... we allow.
22476 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22477 if (!nstyle.length) {
22478 node.removeAttribute('style');
22482 this.iterateChildren(node, this.cleanTableWidths);
22490 domToHTML : function(currentElement, depth, nopadtext) {
22492 depth = depth || 0;
22493 nopadtext = nopadtext || false;
22495 if (!currentElement) {
22496 return this.domToHTML(this.doc.body);
22499 //Roo.log(currentElement);
22501 var allText = false;
22502 var nodeName = currentElement.nodeName;
22503 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22505 if (nodeName == '#text') {
22507 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22512 if (nodeName != 'BODY') {
22515 // Prints the node tagName, such as <A>, <IMG>, etc
22518 for(i = 0; i < currentElement.attributes.length;i++) {
22520 var aname = currentElement.attributes.item(i).name;
22521 if (!currentElement.attributes.item(i).value.length) {
22524 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22527 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22536 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22539 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22544 // Traverse the tree
22546 var currentElementChild = currentElement.childNodes.item(i);
22547 var allText = true;
22548 var innerHTML = '';
22550 while (currentElementChild) {
22551 // Formatting code (indent the tree so it looks nice on the screen)
22552 var nopad = nopadtext;
22553 if (lastnode == 'SPAN') {
22557 if (currentElementChild.nodeName == '#text') {
22558 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22559 toadd = nopadtext ? toadd : toadd.trim();
22560 if (!nopad && toadd.length > 80) {
22561 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22563 innerHTML += toadd;
22566 currentElementChild = currentElement.childNodes.item(i);
22572 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22574 // Recursively traverse the tree structure of the child node
22575 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22576 lastnode = currentElementChild.nodeName;
22578 currentElementChild=currentElement.childNodes.item(i);
22584 // The remaining code is mostly for formatting the tree
22585 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22590 ret+= "</"+tagName+">";
22596 applyBlacklists : function()
22598 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22599 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22603 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22604 if (b.indexOf(tag) > -1) {
22607 this.white.push(tag);
22611 Roo.each(w, function(tag) {
22612 if (b.indexOf(tag) > -1) {
22615 if (this.white.indexOf(tag) > -1) {
22618 this.white.push(tag);
22623 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22624 if (w.indexOf(tag) > -1) {
22627 this.black.push(tag);
22631 Roo.each(b, function(tag) {
22632 if (w.indexOf(tag) > -1) {
22635 if (this.black.indexOf(tag) > -1) {
22638 this.black.push(tag);
22643 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22644 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22648 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22649 if (b.indexOf(tag) > -1) {
22652 this.cwhite.push(tag);
22656 Roo.each(w, function(tag) {
22657 if (b.indexOf(tag) > -1) {
22660 if (this.cwhite.indexOf(tag) > -1) {
22663 this.cwhite.push(tag);
22668 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22669 if (w.indexOf(tag) > -1) {
22672 this.cblack.push(tag);
22676 Roo.each(b, function(tag) {
22677 if (w.indexOf(tag) > -1) {
22680 if (this.cblack.indexOf(tag) > -1) {
22683 this.cblack.push(tag);
22688 setStylesheets : function(stylesheets)
22690 if(typeof(stylesheets) == 'string'){
22691 Roo.get(this.iframe.contentDocument.head).createChild({
22693 rel : 'stylesheet',
22702 Roo.each(stylesheets, function(s) {
22707 Roo.get(_this.iframe.contentDocument.head).createChild({
22709 rel : 'stylesheet',
22718 removeStylesheets : function()
22722 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22727 setStyle : function(style)
22729 Roo.get(this.iframe.contentDocument.head).createChild({
22738 // hide stuff that is not compatible
22752 * @event specialkey
22756 * @cfg {String} fieldClass @hide
22759 * @cfg {String} focusClass @hide
22762 * @cfg {String} autoCreate @hide
22765 * @cfg {String} inputType @hide
22768 * @cfg {String} invalidClass @hide
22771 * @cfg {String} invalidText @hide
22774 * @cfg {String} msgFx @hide
22777 * @cfg {String} validateOnBlur @hide
22781 Roo.HtmlEditorCore.white = [
22782 'area', 'br', 'img', 'input', 'hr', 'wbr',
22784 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22785 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22786 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22787 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22788 'table', 'ul', 'xmp',
22790 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22793 'dir', 'menu', 'ol', 'ul', 'dl',
22799 Roo.HtmlEditorCore.black = [
22800 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22802 'base', 'basefont', 'bgsound', 'blink', 'body',
22803 'frame', 'frameset', 'head', 'html', 'ilayer',
22804 'iframe', 'layer', 'link', 'meta', 'object',
22805 'script', 'style' ,'title', 'xml' // clean later..
22807 Roo.HtmlEditorCore.clean = [
22808 'script', 'style', 'title', 'xml'
22810 Roo.HtmlEditorCore.remove = [
22815 Roo.HtmlEditorCore.ablack = [
22819 Roo.HtmlEditorCore.aclean = [
22820 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22824 Roo.HtmlEditorCore.pwhite= [
22825 'http', 'https', 'mailto'
22828 // white listed style attributes.
22829 Roo.HtmlEditorCore.cwhite= [
22830 // 'text-align', /// default is to allow most things..
22836 // black listed style attributes.
22837 Roo.HtmlEditorCore.cblack= [
22838 // 'font-size' -- this can be set by the project
22842 Roo.HtmlEditorCore.swapCodes =[
22861 * @class Roo.bootstrap.HtmlEditor
22862 * @extends Roo.bootstrap.TextArea
22863 * Bootstrap HtmlEditor class
22866 * Create a new HtmlEditor
22867 * @param {Object} config The config object
22870 Roo.bootstrap.HtmlEditor = function(config){
22871 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22872 if (!this.toolbars) {
22873 this.toolbars = [];
22876 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22879 * @event initialize
22880 * Fires when the editor is fully initialized (including the iframe)
22881 * @param {HtmlEditor} this
22886 * Fires when the editor is first receives the focus. Any insertion must wait
22887 * until after this event.
22888 * @param {HtmlEditor} this
22892 * @event beforesync
22893 * Fires before the textarea is updated with content from the editor iframe. Return false
22894 * to cancel the sync.
22895 * @param {HtmlEditor} this
22896 * @param {String} html
22900 * @event beforepush
22901 * Fires before the iframe editor is updated with content from the textarea. Return false
22902 * to cancel the push.
22903 * @param {HtmlEditor} this
22904 * @param {String} html
22909 * Fires when the textarea is updated with content from the editor iframe.
22910 * @param {HtmlEditor} this
22911 * @param {String} html
22916 * Fires when the iframe editor is updated with content from the textarea.
22917 * @param {HtmlEditor} this
22918 * @param {String} html
22922 * @event editmodechange
22923 * Fires when the editor switches edit modes
22924 * @param {HtmlEditor} this
22925 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22927 editmodechange: true,
22929 * @event editorevent
22930 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22931 * @param {HtmlEditor} this
22935 * @event firstfocus
22936 * Fires when on first focus - needed by toolbars..
22937 * @param {HtmlEditor} this
22942 * Auto save the htmlEditor value as a file into Events
22943 * @param {HtmlEditor} this
22947 * @event savedpreview
22948 * preview the saved version of htmlEditor
22949 * @param {HtmlEditor} this
22956 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22960 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22965 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
22970 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22975 * @cfg {Number} height (in pixels)
22979 * @cfg {Number} width (in pixels)
22984 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22987 stylesheets: false,
22992 // private properties
22993 validationEvent : false,
22995 initialized : false,
22998 onFocus : Roo.emptyFn,
23000 hideMode:'offsets',
23002 tbContainer : false,
23006 toolbarContainer :function() {
23007 return this.wrap.select('.x-html-editor-tb',true).first();
23011 * Protected method that will not generally be called directly. It
23012 * is called when the editor creates its toolbar. Override this method if you need to
23013 * add custom toolbar buttons.
23014 * @param {HtmlEditor} editor
23016 createToolbar : function(){
23017 Roo.log('renewing');
23018 Roo.log("create toolbars");
23020 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23021 this.toolbars[0].render(this.toolbarContainer());
23025 // if (!editor.toolbars || !editor.toolbars.length) {
23026 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23029 // for (var i =0 ; i < editor.toolbars.length;i++) {
23030 // editor.toolbars[i] = Roo.factory(
23031 // typeof(editor.toolbars[i]) == 'string' ?
23032 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23033 // Roo.bootstrap.HtmlEditor);
23034 // editor.toolbars[i].init(editor);
23040 onRender : function(ct, position)
23042 // Roo.log("Call onRender: " + this.xtype);
23044 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23046 this.wrap = this.inputEl().wrap({
23047 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23050 this.editorcore.onRender(ct, position);
23052 if (this.resizable) {
23053 this.resizeEl = new Roo.Resizable(this.wrap, {
23057 minHeight : this.height,
23058 height: this.height,
23059 handles : this.resizable,
23062 resize : function(r, w, h) {
23063 _t.onResize(w,h); // -something
23069 this.createToolbar(this);
23072 if(!this.width && this.resizable){
23073 this.setSize(this.wrap.getSize());
23075 if (this.resizeEl) {
23076 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23077 // should trigger onReize..
23083 onResize : function(w, h)
23085 Roo.log('resize: ' +w + ',' + h );
23086 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23090 if(this.inputEl() ){
23091 if(typeof w == 'number'){
23092 var aw = w - this.wrap.getFrameWidth('lr');
23093 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23096 if(typeof h == 'number'){
23097 var tbh = -11; // fixme it needs to tool bar size!
23098 for (var i =0; i < this.toolbars.length;i++) {
23099 // fixme - ask toolbars for heights?
23100 tbh += this.toolbars[i].el.getHeight();
23101 //if (this.toolbars[i].footer) {
23102 // tbh += this.toolbars[i].footer.el.getHeight();
23110 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23111 ah -= 5; // knock a few pixes off for look..
23112 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23116 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23117 this.editorcore.onResize(ew,eh);
23122 * Toggles the editor between standard and source edit mode.
23123 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23125 toggleSourceEdit : function(sourceEditMode)
23127 this.editorcore.toggleSourceEdit(sourceEditMode);
23129 if(this.editorcore.sourceEditMode){
23130 Roo.log('editor - showing textarea');
23133 // Roo.log(this.syncValue());
23135 this.inputEl().removeClass(['hide', 'x-hidden']);
23136 this.inputEl().dom.removeAttribute('tabIndex');
23137 this.inputEl().focus();
23139 Roo.log('editor - hiding textarea');
23141 // Roo.log(this.pushValue());
23144 this.inputEl().addClass(['hide', 'x-hidden']);
23145 this.inputEl().dom.setAttribute('tabIndex', -1);
23146 //this.deferFocus();
23149 if(this.resizable){
23150 this.setSize(this.wrap.getSize());
23153 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23156 // private (for BoxComponent)
23157 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23159 // private (for BoxComponent)
23160 getResizeEl : function(){
23164 // private (for BoxComponent)
23165 getPositionEl : function(){
23170 initEvents : function(){
23171 this.originalValue = this.getValue();
23175 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23178 // markInvalid : Roo.emptyFn,
23180 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23183 // clearInvalid : Roo.emptyFn,
23185 setValue : function(v){
23186 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23187 this.editorcore.pushValue();
23192 deferFocus : function(){
23193 this.focus.defer(10, this);
23197 focus : function(){
23198 this.editorcore.focus();
23204 onDestroy : function(){
23210 for (var i =0; i < this.toolbars.length;i++) {
23211 // fixme - ask toolbars for heights?
23212 this.toolbars[i].onDestroy();
23215 this.wrap.dom.innerHTML = '';
23216 this.wrap.remove();
23221 onFirstFocus : function(){
23222 //Roo.log("onFirstFocus");
23223 this.editorcore.onFirstFocus();
23224 for (var i =0; i < this.toolbars.length;i++) {
23225 this.toolbars[i].onFirstFocus();
23231 syncValue : function()
23233 this.editorcore.syncValue();
23236 pushValue : function()
23238 this.editorcore.pushValue();
23242 // hide stuff that is not compatible
23256 * @event specialkey
23260 * @cfg {String} fieldClass @hide
23263 * @cfg {String} focusClass @hide
23266 * @cfg {String} autoCreate @hide
23269 * @cfg {String} inputType @hide
23272 * @cfg {String} invalidClass @hide
23275 * @cfg {String} invalidText @hide
23278 * @cfg {String} msgFx @hide
23281 * @cfg {String} validateOnBlur @hide
23290 Roo.namespace('Roo.bootstrap.htmleditor');
23292 * @class Roo.bootstrap.HtmlEditorToolbar1
23297 new Roo.bootstrap.HtmlEditor({
23300 new Roo.bootstrap.HtmlEditorToolbar1({
23301 disable : { fonts: 1 , format: 1, ..., ... , ...],
23307 * @cfg {Object} disable List of elements to disable..
23308 * @cfg {Array} btns List of additional buttons.
23312 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23315 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23318 Roo.apply(this, config);
23320 // default disabled, based on 'good practice'..
23321 this.disable = this.disable || {};
23322 Roo.applyIf(this.disable, {
23325 specialElements : true
23327 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23329 this.editor = config.editor;
23330 this.editorcore = config.editor.editorcore;
23332 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23334 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23335 // dont call parent... till later.
23337 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23342 editorcore : false,
23347 "h1","h2","h3","h4","h5","h6",
23349 "abbr", "acronym", "address", "cite", "samp", "var",
23353 onRender : function(ct, position)
23355 // Roo.log("Call onRender: " + this.xtype);
23357 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23359 this.el.dom.style.marginBottom = '0';
23361 var editorcore = this.editorcore;
23362 var editor= this.editor;
23365 var btn = function(id,cmd , toggle, handler, html){
23367 var event = toggle ? 'toggle' : 'click';
23372 xns: Roo.bootstrap,
23375 enableToggle:toggle !== false,
23377 pressed : toggle ? false : null,
23380 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23381 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23387 // var cb_box = function...
23392 xns: Roo.bootstrap,
23393 glyphicon : 'font',
23397 xns: Roo.bootstrap,
23401 Roo.each(this.formats, function(f) {
23402 style.menu.items.push({
23404 xns: Roo.bootstrap,
23405 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23410 editorcore.insertTag(this.tagname);
23417 children.push(style);
23419 btn('bold',false,true);
23420 btn('italic',false,true);
23421 btn('align-left', 'justifyleft',true);
23422 btn('align-center', 'justifycenter',true);
23423 btn('align-right' , 'justifyright',true);
23424 btn('link', false, false, function(btn) {
23425 //Roo.log("create link?");
23426 var url = prompt(this.createLinkText, this.defaultLinkValue);
23427 if(url && url != 'http:/'+'/'){
23428 this.editorcore.relayCmd('createlink', url);
23431 btn('list','insertunorderedlist',true);
23432 btn('pencil', false,true, function(btn){
23434 this.toggleSourceEdit(btn.pressed);
23437 if (this.editor.btns.length > 0) {
23438 for (var i = 0; i<this.editor.btns.length; i++) {
23439 children.push(this.editor.btns[i]);
23447 xns: Roo.bootstrap,
23452 xns: Roo.bootstrap,
23457 cog.menu.items.push({
23459 xns: Roo.bootstrap,
23460 html : Clean styles,
23465 editorcore.insertTag(this.tagname);
23474 this.xtype = 'NavSimplebar';
23476 for(var i=0;i< children.length;i++) {
23478 this.buttons.add(this.addxtypeChild(children[i]));
23482 editor.on('editorevent', this.updateToolbar, this);
23484 onBtnClick : function(id)
23486 this.editorcore.relayCmd(id);
23487 this.editorcore.focus();
23491 * Protected method that will not generally be called directly. It triggers
23492 * a toolbar update by reading the markup state of the current selection in the editor.
23494 updateToolbar: function(){
23496 if(!this.editorcore.activated){
23497 this.editor.onFirstFocus(); // is this neeed?
23501 var btns = this.buttons;
23502 var doc = this.editorcore.doc;
23503 btns.get('bold').setActive(doc.queryCommandState('bold'));
23504 btns.get('italic').setActive(doc.queryCommandState('italic'));
23505 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23507 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23508 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23509 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23511 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23512 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23515 var ans = this.editorcore.getAllAncestors();
23516 if (this.formatCombo) {
23519 var store = this.formatCombo.store;
23520 this.formatCombo.setValue("");
23521 for (var i =0; i < ans.length;i++) {
23522 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23524 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23532 // hides menus... - so this cant be on a menu...
23533 Roo.bootstrap.MenuMgr.hideAll();
23535 Roo.bootstrap.MenuMgr.hideAll();
23536 //this.editorsyncValue();
23538 onFirstFocus: function() {
23539 this.buttons.each(function(item){
23543 toggleSourceEdit : function(sourceEditMode){
23546 if(sourceEditMode){
23547 Roo.log("disabling buttons");
23548 this.buttons.each( function(item){
23549 if(item.cmd != 'pencil'){
23555 Roo.log("enabling buttons");
23556 if(this.editorcore.initialized){
23557 this.buttons.each( function(item){
23563 Roo.log("calling toggole on editor");
23564 // tell the editor that it's been pressed..
23565 this.editor.toggleSourceEdit(sourceEditMode);
23575 * @class Roo.bootstrap.Table.AbstractSelectionModel
23576 * @extends Roo.util.Observable
23577 * Abstract base class for grid SelectionModels. It provides the interface that should be
23578 * implemented by descendant classes. This class should not be directly instantiated.
23581 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23582 this.locked = false;
23583 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23587 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23588 /** @ignore Called by the grid automatically. Do not call directly. */
23589 init : function(grid){
23595 * Locks the selections.
23598 this.locked = true;
23602 * Unlocks the selections.
23604 unlock : function(){
23605 this.locked = false;
23609 * Returns true if the selections are locked.
23610 * @return {Boolean}
23612 isLocked : function(){
23613 return this.locked;
23617 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23618 * @class Roo.bootstrap.Table.RowSelectionModel
23619 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23620 * It supports multiple selections and keyboard selection/navigation.
23622 * @param {Object} config
23625 Roo.bootstrap.Table.RowSelectionModel = function(config){
23626 Roo.apply(this, config);
23627 this.selections = new Roo.util.MixedCollection(false, function(o){
23632 this.lastActive = false;
23636 * @event selectionchange
23637 * Fires when the selection changes
23638 * @param {SelectionModel} this
23640 "selectionchange" : true,
23642 * @event afterselectionchange
23643 * Fires after the selection changes (eg. by key press or clicking)
23644 * @param {SelectionModel} this
23646 "afterselectionchange" : true,
23648 * @event beforerowselect
23649 * Fires when a row is selected being selected, return false to cancel.
23650 * @param {SelectionModel} this
23651 * @param {Number} rowIndex The selected index
23652 * @param {Boolean} keepExisting False if other selections will be cleared
23654 "beforerowselect" : true,
23657 * Fires when a row is selected.
23658 * @param {SelectionModel} this
23659 * @param {Number} rowIndex The selected index
23660 * @param {Roo.data.Record} r The record
23662 "rowselect" : true,
23664 * @event rowdeselect
23665 * Fires when a row is deselected.
23666 * @param {SelectionModel} this
23667 * @param {Number} rowIndex The selected index
23669 "rowdeselect" : true
23671 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23672 this.locked = false;
23675 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23677 * @cfg {Boolean} singleSelect
23678 * True to allow selection of only one row at a time (defaults to false)
23680 singleSelect : false,
23683 initEvents : function()
23686 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23687 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23688 //}else{ // allow click to work like normal
23689 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23691 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23692 this.grid.on("rowclick", this.handleMouseDown, this);
23694 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23695 "up" : function(e){
23697 this.selectPrevious(e.shiftKey);
23698 }else if(this.last !== false && this.lastActive !== false){
23699 var last = this.last;
23700 this.selectRange(this.last, this.lastActive-1);
23701 this.grid.getView().focusRow(this.lastActive);
23702 if(last !== false){
23706 this.selectFirstRow();
23708 this.fireEvent("afterselectionchange", this);
23710 "down" : function(e){
23712 this.selectNext(e.shiftKey);
23713 }else if(this.last !== false && this.lastActive !== false){
23714 var last = this.last;
23715 this.selectRange(this.last, this.lastActive+1);
23716 this.grid.getView().focusRow(this.lastActive);
23717 if(last !== false){
23721 this.selectFirstRow();
23723 this.fireEvent("afterselectionchange", this);
23727 this.grid.store.on('load', function(){
23728 this.selections.clear();
23731 var view = this.grid.view;
23732 view.on("refresh", this.onRefresh, this);
23733 view.on("rowupdated", this.onRowUpdated, this);
23734 view.on("rowremoved", this.onRemove, this);
23739 onRefresh : function()
23741 var ds = this.grid.store, i, v = this.grid.view;
23742 var s = this.selections;
23743 s.each(function(r){
23744 if((i = ds.indexOfId(r.id)) != -1){
23753 onRemove : function(v, index, r){
23754 this.selections.remove(r);
23758 onRowUpdated : function(v, index, r){
23759 if(this.isSelected(r)){
23760 v.onRowSelect(index);
23766 * @param {Array} records The records to select
23767 * @param {Boolean} keepExisting (optional) True to keep existing selections
23769 selectRecords : function(records, keepExisting)
23772 this.clearSelections();
23774 var ds = this.grid.store;
23775 for(var i = 0, len = records.length; i < len; i++){
23776 this.selectRow(ds.indexOf(records[i]), true);
23781 * Gets the number of selected rows.
23784 getCount : function(){
23785 return this.selections.length;
23789 * Selects the first row in the grid.
23791 selectFirstRow : function(){
23796 * Select the last row.
23797 * @param {Boolean} keepExisting (optional) True to keep existing selections
23799 selectLastRow : function(keepExisting){
23800 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23801 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23805 * Selects the row immediately following the last selected row.
23806 * @param {Boolean} keepExisting (optional) True to keep existing selections
23808 selectNext : function(keepExisting)
23810 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23811 this.selectRow(this.last+1, keepExisting);
23812 this.grid.getView().focusRow(this.last);
23817 * Selects the row that precedes the last selected row.
23818 * @param {Boolean} keepExisting (optional) True to keep existing selections
23820 selectPrevious : function(keepExisting){
23822 this.selectRow(this.last-1, keepExisting);
23823 this.grid.getView().focusRow(this.last);
23828 * Returns the selected records
23829 * @return {Array} Array of selected records
23831 getSelections : function(){
23832 return [].concat(this.selections.items);
23836 * Returns the first selected record.
23839 getSelected : function(){
23840 return this.selections.itemAt(0);
23845 * Clears all selections.
23847 clearSelections : function(fast)
23853 var ds = this.grid.store;
23854 var s = this.selections;
23855 s.each(function(r){
23856 this.deselectRow(ds.indexOfId(r.id));
23860 this.selections.clear();
23867 * Selects all rows.
23869 selectAll : function(){
23873 this.selections.clear();
23874 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23875 this.selectRow(i, true);
23880 * Returns True if there is a selection.
23881 * @return {Boolean}
23883 hasSelection : function(){
23884 return this.selections.length > 0;
23888 * Returns True if the specified row is selected.
23889 * @param {Number/Record} record The record or index of the record to check
23890 * @return {Boolean}
23892 isSelected : function(index){
23893 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23894 return (r && this.selections.key(r.id) ? true : false);
23898 * Returns True if the specified record id is selected.
23899 * @param {String} id The id of record to check
23900 * @return {Boolean}
23902 isIdSelected : function(id){
23903 return (this.selections.key(id) ? true : false);
23908 handleMouseDBClick : function(e, t){
23912 handleMouseDown : function(e, t)
23914 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23915 if(this.isLocked() || rowIndex < 0 ){
23918 if(e.shiftKey && this.last !== false){
23919 var last = this.last;
23920 this.selectRange(last, rowIndex, e.ctrlKey);
23921 this.last = last; // reset the last
23925 var isSelected = this.isSelected(rowIndex);
23926 //Roo.log("select row:" + rowIndex);
23928 this.deselectRow(rowIndex);
23930 this.selectRow(rowIndex, true);
23934 if(e.button !== 0 && isSelected){
23935 alert('rowIndex 2: ' + rowIndex);
23936 view.focusRow(rowIndex);
23937 }else if(e.ctrlKey && isSelected){
23938 this.deselectRow(rowIndex);
23939 }else if(!isSelected){
23940 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23941 view.focusRow(rowIndex);
23945 this.fireEvent("afterselectionchange", this);
23948 handleDragableRowClick : function(grid, rowIndex, e)
23950 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23951 this.selectRow(rowIndex, false);
23952 grid.view.focusRow(rowIndex);
23953 this.fireEvent("afterselectionchange", this);
23958 * Selects multiple rows.
23959 * @param {Array} rows Array of the indexes of the row to select
23960 * @param {Boolean} keepExisting (optional) True to keep existing selections
23962 selectRows : function(rows, keepExisting){
23964 this.clearSelections();
23966 for(var i = 0, len = rows.length; i < len; i++){
23967 this.selectRow(rows[i], true);
23972 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23973 * @param {Number} startRow The index of the first row in the range
23974 * @param {Number} endRow The index of the last row in the range
23975 * @param {Boolean} keepExisting (optional) True to retain existing selections
23977 selectRange : function(startRow, endRow, keepExisting){
23982 this.clearSelections();
23984 if(startRow <= endRow){
23985 for(var i = startRow; i <= endRow; i++){
23986 this.selectRow(i, true);
23989 for(var i = startRow; i >= endRow; i--){
23990 this.selectRow(i, true);
23996 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23997 * @param {Number} startRow The index of the first row in the range
23998 * @param {Number} endRow The index of the last row in the range
24000 deselectRange : function(startRow, endRow, preventViewNotify){
24004 for(var i = startRow; i <= endRow; i++){
24005 this.deselectRow(i, preventViewNotify);
24011 * @param {Number} row The index of the row to select
24012 * @param {Boolean} keepExisting (optional) True to keep existing selections
24014 selectRow : function(index, keepExisting, preventViewNotify)
24016 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24019 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24020 if(!keepExisting || this.singleSelect){
24021 this.clearSelections();
24024 var r = this.grid.store.getAt(index);
24025 //console.log('selectRow - record id :' + r.id);
24027 this.selections.add(r);
24028 this.last = this.lastActive = index;
24029 if(!preventViewNotify){
24030 var proxy = new Roo.Element(
24031 this.grid.getRowDom(index)
24033 proxy.addClass('bg-info info');
24035 this.fireEvent("rowselect", this, index, r);
24036 this.fireEvent("selectionchange", this);
24042 * @param {Number} row The index of the row to deselect
24044 deselectRow : function(index, preventViewNotify)
24049 if(this.last == index){
24052 if(this.lastActive == index){
24053 this.lastActive = false;
24056 var r = this.grid.store.getAt(index);
24061 this.selections.remove(r);
24062 //.console.log('deselectRow - record id :' + r.id);
24063 if(!preventViewNotify){
24065 var proxy = new Roo.Element(
24066 this.grid.getRowDom(index)
24068 proxy.removeClass('bg-info info');
24070 this.fireEvent("rowdeselect", this, index);
24071 this.fireEvent("selectionchange", this);
24075 restoreLast : function(){
24077 this.last = this._last;
24082 acceptsNav : function(row, col, cm){
24083 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24087 onEditorKey : function(field, e){
24088 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24093 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24095 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24097 }else if(k == e.ENTER && !e.ctrlKey){
24101 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24103 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24105 }else if(k == e.ESC){
24109 g.startEditing(newCell[0], newCell[1]);
24115 * Ext JS Library 1.1.1
24116 * Copyright(c) 2006-2007, Ext JS, LLC.
24118 * Originally Released Under LGPL - original licence link has changed is not relivant.
24121 * <script type="text/javascript">
24125 * @class Roo.bootstrap.PagingToolbar
24126 * @extends Roo.bootstrap.NavSimplebar
24127 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24129 * Create a new PagingToolbar
24130 * @param {Object} config The config object
24131 * @param {Roo.data.Store} store
24133 Roo.bootstrap.PagingToolbar = function(config)
24135 // old args format still supported... - xtype is prefered..
24136 // created from xtype...
24138 this.ds = config.dataSource;
24140 if (config.store && !this.ds) {
24141 this.store= Roo.factory(config.store, Roo.data);
24142 this.ds = this.store;
24143 this.ds.xmodule = this.xmodule || false;
24146 this.toolbarItems = [];
24147 if (config.items) {
24148 this.toolbarItems = config.items;
24151 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24156 this.bind(this.ds);
24159 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24163 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24165 * @cfg {Roo.data.Store} dataSource
24166 * The underlying data store providing the paged data
24169 * @cfg {String/HTMLElement/Element} container
24170 * container The id or element that will contain the toolbar
24173 * @cfg {Boolean} displayInfo
24174 * True to display the displayMsg (defaults to false)
24177 * @cfg {Number} pageSize
24178 * The number of records to display per page (defaults to 20)
24182 * @cfg {String} displayMsg
24183 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24185 displayMsg : 'Displaying {0} - {1} of {2}',
24187 * @cfg {String} emptyMsg
24188 * The message to display when no records are found (defaults to "No data to display")
24190 emptyMsg : 'No data to display',
24192 * Customizable piece of the default paging text (defaults to "Page")
24195 beforePageText : "Page",
24197 * Customizable piece of the default paging text (defaults to "of %0")
24200 afterPageText : "of {0}",
24202 * Customizable piece of the default paging text (defaults to "First Page")
24205 firstText : "First Page",
24207 * Customizable piece of the default paging text (defaults to "Previous Page")
24210 prevText : "Previous Page",
24212 * Customizable piece of the default paging text (defaults to "Next Page")
24215 nextText : "Next Page",
24217 * Customizable piece of the default paging text (defaults to "Last Page")
24220 lastText : "Last Page",
24222 * Customizable piece of the default paging text (defaults to "Refresh")
24225 refreshText : "Refresh",
24229 onRender : function(ct, position)
24231 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24232 this.navgroup.parentId = this.id;
24233 this.navgroup.onRender(this.el, null);
24234 // add the buttons to the navgroup
24236 if(this.displayInfo){
24237 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24238 this.displayEl = this.el.select('.x-paging-info', true).first();
24239 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24240 // this.displayEl = navel.el.select('span',true).first();
24246 Roo.each(_this.buttons, function(e){ // this might need to use render????
24247 Roo.factory(e).onRender(_this.el, null);
24251 Roo.each(_this.toolbarItems, function(e) {
24252 _this.navgroup.addItem(e);
24256 this.first = this.navgroup.addItem({
24257 tooltip: this.firstText,
24259 icon : 'fa fa-backward',
24261 preventDefault: true,
24262 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24265 this.prev = this.navgroup.addItem({
24266 tooltip: this.prevText,
24268 icon : 'fa fa-step-backward',
24270 preventDefault: true,
24271 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24273 //this.addSeparator();
24276 var field = this.navgroup.addItem( {
24278 cls : 'x-paging-position',
24280 html : this.beforePageText +
24281 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24282 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24285 this.field = field.el.select('input', true).first();
24286 this.field.on("keydown", this.onPagingKeydown, this);
24287 this.field.on("focus", function(){this.dom.select();});
24290 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24291 //this.field.setHeight(18);
24292 //this.addSeparator();
24293 this.next = this.navgroup.addItem({
24294 tooltip: this.nextText,
24296 html : ' <i class="fa fa-step-forward">',
24298 preventDefault: true,
24299 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24301 this.last = this.navgroup.addItem({
24302 tooltip: this.lastText,
24303 icon : 'fa fa-forward',
24306 preventDefault: true,
24307 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24309 //this.addSeparator();
24310 this.loading = this.navgroup.addItem({
24311 tooltip: this.refreshText,
24312 icon: 'fa fa-refresh',
24313 preventDefault: true,
24314 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24320 updateInfo : function(){
24321 if(this.displayEl){
24322 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24323 var msg = count == 0 ?
24327 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24329 this.displayEl.update(msg);
24334 onLoad : function(ds, r, o)
24336 this.cursor = o.params ? o.params.start : 0;
24337 var d = this.getPageData(),
24342 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24343 this.field.dom.value = ap;
24344 this.first.setDisabled(ap == 1);
24345 this.prev.setDisabled(ap == 1);
24346 this.next.setDisabled(ap == ps);
24347 this.last.setDisabled(ap == ps);
24348 this.loading.enable();
24353 getPageData : function(){
24354 var total = this.ds.getTotalCount();
24357 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24358 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24363 onLoadError : function(){
24364 this.loading.enable();
24368 onPagingKeydown : function(e){
24369 var k = e.getKey();
24370 var d = this.getPageData();
24372 var v = this.field.dom.value, pageNum;
24373 if(!v || isNaN(pageNum = parseInt(v, 10))){
24374 this.field.dom.value = d.activePage;
24377 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24378 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24381 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))
24383 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24384 this.field.dom.value = pageNum;
24385 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24388 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24390 var v = this.field.dom.value, pageNum;
24391 var increment = (e.shiftKey) ? 10 : 1;
24392 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24395 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24396 this.field.dom.value = d.activePage;
24399 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24401 this.field.dom.value = parseInt(v, 10) + increment;
24402 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24403 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24410 beforeLoad : function(){
24412 this.loading.disable();
24417 onClick : function(which){
24426 ds.load({params:{start: 0, limit: this.pageSize}});
24429 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24432 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24435 var total = ds.getTotalCount();
24436 var extra = total % this.pageSize;
24437 var lastStart = extra ? (total - extra) : total-this.pageSize;
24438 ds.load({params:{start: lastStart, limit: this.pageSize}});
24441 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24447 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24448 * @param {Roo.data.Store} store The data store to unbind
24450 unbind : function(ds){
24451 ds.un("beforeload", this.beforeLoad, this);
24452 ds.un("load", this.onLoad, this);
24453 ds.un("loadexception", this.onLoadError, this);
24454 ds.un("remove", this.updateInfo, this);
24455 ds.un("add", this.updateInfo, this);
24456 this.ds = undefined;
24460 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24461 * @param {Roo.data.Store} store The data store to bind
24463 bind : function(ds){
24464 ds.on("beforeload", this.beforeLoad, this);
24465 ds.on("load", this.onLoad, this);
24466 ds.on("loadexception", this.onLoadError, this);
24467 ds.on("remove", this.updateInfo, this);
24468 ds.on("add", this.updateInfo, this);
24479 * @class Roo.bootstrap.MessageBar
24480 * @extends Roo.bootstrap.Component
24481 * Bootstrap MessageBar class
24482 * @cfg {String} html contents of the MessageBar
24483 * @cfg {String} weight (info | success | warning | danger) default info
24484 * @cfg {String} beforeClass insert the bar before the given class
24485 * @cfg {Boolean} closable (true | false) default false
24486 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24489 * Create a new Element
24490 * @param {Object} config The config object
24493 Roo.bootstrap.MessageBar = function(config){
24494 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24497 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24503 beforeClass: 'bootstrap-sticky-wrap',
24505 getAutoCreate : function(){
24509 cls: 'alert alert-dismissable alert-' + this.weight,
24514 html: this.html || ''
24520 cfg.cls += ' alert-messages-fixed';
24534 onRender : function(ct, position)
24536 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24539 var cfg = Roo.apply({}, this.getAutoCreate());
24543 cfg.cls += ' ' + this.cls;
24546 cfg.style = this.style;
24548 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24550 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24553 this.el.select('>button.close').on('click', this.hide, this);
24559 if (!this.rendered) {
24565 this.fireEvent('show', this);
24571 if (!this.rendered) {
24577 this.fireEvent('hide', this);
24580 update : function()
24582 // var e = this.el.dom.firstChild;
24584 // if(this.closable){
24585 // e = e.nextSibling;
24588 // e.data = this.html || '';
24590 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24606 * @class Roo.bootstrap.Graph
24607 * @extends Roo.bootstrap.Component
24608 * Bootstrap Graph class
24612 @cfg {String} graphtype bar | vbar | pie
24613 @cfg {number} g_x coodinator | centre x (pie)
24614 @cfg {number} g_y coodinator | centre y (pie)
24615 @cfg {number} g_r radius (pie)
24616 @cfg {number} g_height height of the chart (respected by all elements in the set)
24617 @cfg {number} g_width width of the chart (respected by all elements in the set)
24618 @cfg {Object} title The title of the chart
24621 -opts (object) options for the chart
24623 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24624 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24626 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.
24627 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24629 o stretch (boolean)
24631 -opts (object) options for the pie
24634 o startAngle (number)
24635 o endAngle (number)
24639 * Create a new Input
24640 * @param {Object} config The config object
24643 Roo.bootstrap.Graph = function(config){
24644 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24650 * The img click event for the img.
24651 * @param {Roo.EventObject} e
24657 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24668 //g_colors: this.colors,
24675 getAutoCreate : function(){
24686 onRender : function(ct,position){
24689 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24691 if (typeof(Raphael) == 'undefined') {
24692 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24696 this.raphael = Raphael(this.el.dom);
24698 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24699 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24700 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24701 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24703 r.text(160, 10, "Single Series Chart").attr(txtattr);
24704 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24705 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24706 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24708 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24709 r.barchart(330, 10, 300, 220, data1);
24710 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24711 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24714 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24715 // r.barchart(30, 30, 560, 250, xdata, {
24716 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24717 // axis : "0 0 1 1",
24718 // axisxlabels : xdata
24719 // //yvalues : cols,
24722 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24724 // this.load(null,xdata,{
24725 // axis : "0 0 1 1",
24726 // axisxlabels : xdata
24731 load : function(graphtype,xdata,opts)
24733 this.raphael.clear();
24735 graphtype = this.graphtype;
24740 var r = this.raphael,
24741 fin = function () {
24742 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24744 fout = function () {
24745 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24747 pfin = function() {
24748 this.sector.stop();
24749 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24752 this.label[0].stop();
24753 this.label[0].attr({ r: 7.5 });
24754 this.label[1].attr({ "font-weight": 800 });
24757 pfout = function() {
24758 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24761 this.label[0].animate({ r: 5 }, 500, "bounce");
24762 this.label[1].attr({ "font-weight": 400 });
24768 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24771 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24774 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24775 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24777 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24784 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24789 setTitle: function(o)
24794 initEvents: function() {
24797 this.el.on('click', this.onClick, this);
24801 onClick : function(e)
24803 Roo.log('img onclick');
24804 this.fireEvent('click', this, e);
24816 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24819 * @class Roo.bootstrap.dash.NumberBox
24820 * @extends Roo.bootstrap.Component
24821 * Bootstrap NumberBox class
24822 * @cfg {String} headline Box headline
24823 * @cfg {String} content Box content
24824 * @cfg {String} icon Box icon
24825 * @cfg {String} footer Footer text
24826 * @cfg {String} fhref Footer href
24829 * Create a new NumberBox
24830 * @param {Object} config The config object
24834 Roo.bootstrap.dash.NumberBox = function(config){
24835 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24839 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24848 getAutoCreate : function(){
24852 cls : 'small-box ',
24860 cls : 'roo-headline',
24861 html : this.headline
24865 cls : 'roo-content',
24866 html : this.content
24880 cls : 'ion ' + this.icon
24889 cls : 'small-box-footer',
24890 href : this.fhref || '#',
24894 cfg.cn.push(footer);
24901 onRender : function(ct,position){
24902 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24909 setHeadline: function (value)
24911 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24914 setFooter: function (value, href)
24916 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24919 this.el.select('a.small-box-footer',true).first().attr('href', href);
24924 setContent: function (value)
24926 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24929 initEvents: function()
24943 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24946 * @class Roo.bootstrap.dash.TabBox
24947 * @extends Roo.bootstrap.Component
24948 * Bootstrap TabBox class
24949 * @cfg {String} title Title of the TabBox
24950 * @cfg {String} icon Icon of the TabBox
24951 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24952 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24955 * Create a new TabBox
24956 * @param {Object} config The config object
24960 Roo.bootstrap.dash.TabBox = function(config){
24961 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24966 * When a pane is added
24967 * @param {Roo.bootstrap.dash.TabPane} pane
24971 * @event activatepane
24972 * When a pane is activated
24973 * @param {Roo.bootstrap.dash.TabPane} pane
24975 "activatepane" : true
24983 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24988 tabScrollable : false,
24990 getChildContainer : function()
24992 return this.el.select('.tab-content', true).first();
24995 getAutoCreate : function(){
24999 cls: 'pull-left header',
25007 cls: 'fa ' + this.icon
25013 cls: 'nav nav-tabs pull-right',
25019 if(this.tabScrollable){
25026 cls: 'nav nav-tabs pull-right',
25037 cls: 'nav-tabs-custom',
25042 cls: 'tab-content no-padding',
25050 initEvents : function()
25052 //Roo.log('add add pane handler');
25053 this.on('addpane', this.onAddPane, this);
25056 * Updates the box title
25057 * @param {String} html to set the title to.
25059 setTitle : function(value)
25061 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25063 onAddPane : function(pane)
25065 this.panes.push(pane);
25066 //Roo.log('addpane');
25068 // tabs are rendere left to right..
25069 if(!this.showtabs){
25073 var ctr = this.el.select('.nav-tabs', true).first();
25076 var existing = ctr.select('.nav-tab',true);
25077 var qty = existing.getCount();;
25080 var tab = ctr.createChild({
25082 cls : 'nav-tab' + (qty ? '' : ' active'),
25090 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25093 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25095 pane.el.addClass('active');
25100 onTabClick : function(ev,un,ob,pane)
25102 //Roo.log('tab - prev default');
25103 ev.preventDefault();
25106 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25107 pane.tab.addClass('active');
25108 //Roo.log(pane.title);
25109 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25110 // technically we should have a deactivate event.. but maybe add later.
25111 // and it should not de-activate the selected tab...
25112 this.fireEvent('activatepane', pane);
25113 pane.el.addClass('active');
25114 pane.fireEvent('activate');
25119 getActivePane : function()
25122 Roo.each(this.panes, function(p) {
25123 if(p.el.hasClass('active')){
25144 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25146 * @class Roo.bootstrap.TabPane
25147 * @extends Roo.bootstrap.Component
25148 * Bootstrap TabPane class
25149 * @cfg {Boolean} active (false | true) Default false
25150 * @cfg {String} title title of panel
25154 * Create a new TabPane
25155 * @param {Object} config The config object
25158 Roo.bootstrap.dash.TabPane = function(config){
25159 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25165 * When a pane is activated
25166 * @param {Roo.bootstrap.dash.TabPane} pane
25173 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25178 // the tabBox that this is attached to.
25181 getAutoCreate : function()
25189 cfg.cls += ' active';
25194 initEvents : function()
25196 //Roo.log('trigger add pane handler');
25197 this.parent().fireEvent('addpane', this)
25201 * Updates the tab title
25202 * @param {String} html to set the title to.
25204 setTitle: function(str)
25210 this.tab.select('a', true).first().dom.innerHTML = str;
25227 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25230 * @class Roo.bootstrap.menu.Menu
25231 * @extends Roo.bootstrap.Component
25232 * Bootstrap Menu class - container for Menu
25233 * @cfg {String} html Text of the menu
25234 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25235 * @cfg {String} icon Font awesome icon
25236 * @cfg {String} pos Menu align to (top | bottom) default bottom
25240 * Create a new Menu
25241 * @param {Object} config The config object
25245 Roo.bootstrap.menu.Menu = function(config){
25246 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25250 * @event beforeshow
25251 * Fires before this menu is displayed
25252 * @param {Roo.bootstrap.menu.Menu} this
25256 * @event beforehide
25257 * Fires before this menu is hidden
25258 * @param {Roo.bootstrap.menu.Menu} this
25263 * Fires after this menu is displayed
25264 * @param {Roo.bootstrap.menu.Menu} this
25269 * Fires after this menu is hidden
25270 * @param {Roo.bootstrap.menu.Menu} this
25275 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25276 * @param {Roo.bootstrap.menu.Menu} this
25277 * @param {Roo.EventObject} e
25284 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25288 weight : 'default',
25293 getChildContainer : function() {
25294 if(this.isSubMenu){
25298 return this.el.select('ul.dropdown-menu', true).first();
25301 getAutoCreate : function()
25306 cls : 'roo-menu-text',
25314 cls : 'fa ' + this.icon
25325 cls : 'dropdown-button btn btn-' + this.weight,
25330 cls : 'dropdown-toggle btn btn-' + this.weight,
25340 cls : 'dropdown-menu'
25346 if(this.pos == 'top'){
25347 cfg.cls += ' dropup';
25350 if(this.isSubMenu){
25353 cls : 'dropdown-menu'
25360 onRender : function(ct, position)
25362 this.isSubMenu = ct.hasClass('dropdown-submenu');
25364 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25367 initEvents : function()
25369 if(this.isSubMenu){
25373 this.hidden = true;
25375 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25376 this.triggerEl.on('click', this.onTriggerPress, this);
25378 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25379 this.buttonEl.on('click', this.onClick, this);
25385 if(this.isSubMenu){
25389 return this.el.select('ul.dropdown-menu', true).first();
25392 onClick : function(e)
25394 this.fireEvent("click", this, e);
25397 onTriggerPress : function(e)
25399 if (this.isVisible()) {
25406 isVisible : function(){
25407 return !this.hidden;
25412 this.fireEvent("beforeshow", this);
25414 this.hidden = false;
25415 this.el.addClass('open');
25417 Roo.get(document).on("mouseup", this.onMouseUp, this);
25419 this.fireEvent("show", this);
25426 this.fireEvent("beforehide", this);
25428 this.hidden = true;
25429 this.el.removeClass('open');
25431 Roo.get(document).un("mouseup", this.onMouseUp);
25433 this.fireEvent("hide", this);
25436 onMouseUp : function()
25450 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25453 * @class Roo.bootstrap.menu.Item
25454 * @extends Roo.bootstrap.Component
25455 * Bootstrap MenuItem class
25456 * @cfg {Boolean} submenu (true | false) default false
25457 * @cfg {String} html text of the item
25458 * @cfg {String} href the link
25459 * @cfg {Boolean} disable (true | false) default false
25460 * @cfg {Boolean} preventDefault (true | false) default true
25461 * @cfg {String} icon Font awesome icon
25462 * @cfg {String} pos Submenu align to (left | right) default right
25466 * Create a new Item
25467 * @param {Object} config The config object
25471 Roo.bootstrap.menu.Item = function(config){
25472 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25476 * Fires when the mouse is hovering over this menu
25477 * @param {Roo.bootstrap.menu.Item} this
25478 * @param {Roo.EventObject} e
25483 * Fires when the mouse exits this menu
25484 * @param {Roo.bootstrap.menu.Item} this
25485 * @param {Roo.EventObject} e
25491 * The raw click event for the entire grid.
25492 * @param {Roo.EventObject} e
25498 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25503 preventDefault: true,
25508 getAutoCreate : function()
25513 cls : 'roo-menu-item-text',
25521 cls : 'fa ' + this.icon
25530 href : this.href || '#',
25537 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25541 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25543 if(this.pos == 'left'){
25544 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25551 initEvents : function()
25553 this.el.on('mouseover', this.onMouseOver, this);
25554 this.el.on('mouseout', this.onMouseOut, this);
25556 this.el.select('a', true).first().on('click', this.onClick, this);
25560 onClick : function(e)
25562 if(this.preventDefault){
25563 e.preventDefault();
25566 this.fireEvent("click", this, e);
25569 onMouseOver : function(e)
25571 if(this.submenu && this.pos == 'left'){
25572 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25575 this.fireEvent("mouseover", this, e);
25578 onMouseOut : function(e)
25580 this.fireEvent("mouseout", this, e);
25592 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25595 * @class Roo.bootstrap.menu.Separator
25596 * @extends Roo.bootstrap.Component
25597 * Bootstrap Separator class
25600 * Create a new Separator
25601 * @param {Object} config The config object
25605 Roo.bootstrap.menu.Separator = function(config){
25606 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25609 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25611 getAutoCreate : function(){
25632 * @class Roo.bootstrap.Tooltip
25633 * Bootstrap Tooltip class
25634 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25635 * to determine which dom element triggers the tooltip.
25637 * It needs to add support for additional attributes like tooltip-position
25640 * Create a new Toolti
25641 * @param {Object} config The config object
25644 Roo.bootstrap.Tooltip = function(config){
25645 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25647 this.alignment = Roo.bootstrap.Tooltip.alignment;
25649 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25650 this.alignment = config.alignment;
25655 Roo.apply(Roo.bootstrap.Tooltip, {
25657 * @function init initialize tooltip monitoring.
25661 currentTip : false,
25662 currentRegion : false,
25668 Roo.get(document).on('mouseover', this.enter ,this);
25669 Roo.get(document).on('mouseout', this.leave, this);
25672 this.currentTip = new Roo.bootstrap.Tooltip();
25675 enter : function(ev)
25677 var dom = ev.getTarget();
25679 //Roo.log(['enter',dom]);
25680 var el = Roo.fly(dom);
25681 if (this.currentEl) {
25683 //Roo.log(this.currentEl);
25684 //Roo.log(this.currentEl.contains(dom));
25685 if (this.currentEl == el) {
25688 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25694 if (this.currentTip.el) {
25695 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25699 if(!el || el.dom == document){
25705 // you can not look for children, as if el is the body.. then everythign is the child..
25706 if (!el.attr('tooltip')) { //
25707 if (!el.select("[tooltip]").elements.length) {
25710 // is the mouse over this child...?
25711 bindEl = el.select("[tooltip]").first();
25712 var xy = ev.getXY();
25713 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25714 //Roo.log("not in region.");
25717 //Roo.log("child element over..");
25720 this.currentEl = bindEl;
25721 this.currentTip.bind(bindEl);
25722 this.currentRegion = Roo.lib.Region.getRegion(dom);
25723 this.currentTip.enter();
25726 leave : function(ev)
25728 var dom = ev.getTarget();
25729 //Roo.log(['leave',dom]);
25730 if (!this.currentEl) {
25735 if (dom != this.currentEl.dom) {
25738 var xy = ev.getXY();
25739 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25742 // only activate leave if mouse cursor is outside... bounding box..
25747 if (this.currentTip) {
25748 this.currentTip.leave();
25750 //Roo.log('clear currentEl');
25751 this.currentEl = false;
25756 'left' : ['r-l', [-2,0], 'right'],
25757 'right' : ['l-r', [2,0], 'left'],
25758 'bottom' : ['t-b', [0,2], 'top'],
25759 'top' : [ 'b-t', [0,-2], 'bottom']
25765 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25770 delay : null, // can be { show : 300 , hide: 500}
25774 hoverState : null, //???
25776 placement : 'bottom',
25780 getAutoCreate : function(){
25787 cls : 'tooltip-arrow'
25790 cls : 'tooltip-inner'
25797 bind : function(el)
25803 enter : function () {
25805 if (this.timeout != null) {
25806 clearTimeout(this.timeout);
25809 this.hoverState = 'in';
25810 //Roo.log("enter - show");
25811 if (!this.delay || !this.delay.show) {
25816 this.timeout = setTimeout(function () {
25817 if (_t.hoverState == 'in') {
25820 }, this.delay.show);
25824 clearTimeout(this.timeout);
25826 this.hoverState = 'out';
25827 if (!this.delay || !this.delay.hide) {
25833 this.timeout = setTimeout(function () {
25834 //Roo.log("leave - timeout");
25836 if (_t.hoverState == 'out') {
25838 Roo.bootstrap.Tooltip.currentEl = false;
25843 show : function (msg)
25846 this.render(document.body);
25849 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25851 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25853 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25855 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25857 var placement = typeof this.placement == 'function' ?
25858 this.placement.call(this, this.el, on_el) :
25861 var autoToken = /\s?auto?\s?/i;
25862 var autoPlace = autoToken.test(placement);
25864 placement = placement.replace(autoToken, '') || 'top';
25868 //this.el.setXY([0,0]);
25870 //this.el.dom.style.display='block';
25872 //this.el.appendTo(on_el);
25874 var p = this.getPosition();
25875 var box = this.el.getBox();
25881 var align = this.alignment[placement];
25883 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25885 if(placement == 'top' || placement == 'bottom'){
25887 placement = 'right';
25890 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25891 placement = 'left';
25894 var scroll = Roo.select('body', true).first().getScroll();
25896 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25902 this.el.alignTo(this.bindEl, align[0],align[1]);
25903 //var arrow = this.el.select('.arrow',true).first();
25904 //arrow.set(align[2],
25906 this.el.addClass(placement);
25908 this.el.addClass('in fade');
25910 this.hoverState = null;
25912 if (this.el.hasClass('fade')) {
25923 //this.el.setXY([0,0]);
25924 this.el.removeClass('in');
25940 * @class Roo.bootstrap.LocationPicker
25941 * @extends Roo.bootstrap.Component
25942 * Bootstrap LocationPicker class
25943 * @cfg {Number} latitude Position when init default 0
25944 * @cfg {Number} longitude Position when init default 0
25945 * @cfg {Number} zoom default 15
25946 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25947 * @cfg {Boolean} mapTypeControl default false
25948 * @cfg {Boolean} disableDoubleClickZoom default false
25949 * @cfg {Boolean} scrollwheel default true
25950 * @cfg {Boolean} streetViewControl default false
25951 * @cfg {Number} radius default 0
25952 * @cfg {String} locationName
25953 * @cfg {Boolean} draggable default true
25954 * @cfg {Boolean} enableAutocomplete default false
25955 * @cfg {Boolean} enableReverseGeocode default true
25956 * @cfg {String} markerTitle
25959 * Create a new LocationPicker
25960 * @param {Object} config The config object
25964 Roo.bootstrap.LocationPicker = function(config){
25966 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25971 * Fires when the picker initialized.
25972 * @param {Roo.bootstrap.LocationPicker} this
25973 * @param {Google Location} location
25977 * @event positionchanged
25978 * Fires when the picker position changed.
25979 * @param {Roo.bootstrap.LocationPicker} this
25980 * @param {Google Location} location
25982 positionchanged : true,
25985 * Fires when the map resize.
25986 * @param {Roo.bootstrap.LocationPicker} this
25991 * Fires when the map show.
25992 * @param {Roo.bootstrap.LocationPicker} this
25997 * Fires when the map hide.
25998 * @param {Roo.bootstrap.LocationPicker} this
26003 * Fires when click the map.
26004 * @param {Roo.bootstrap.LocationPicker} this
26005 * @param {Map event} e
26009 * @event mapRightClick
26010 * Fires when right click the map.
26011 * @param {Roo.bootstrap.LocationPicker} this
26012 * @param {Map event} e
26014 mapRightClick : true,
26016 * @event markerClick
26017 * Fires when click the marker.
26018 * @param {Roo.bootstrap.LocationPicker} this
26019 * @param {Map event} e
26021 markerClick : true,
26023 * @event markerRightClick
26024 * Fires when right click the marker.
26025 * @param {Roo.bootstrap.LocationPicker} this
26026 * @param {Map event} e
26028 markerRightClick : true,
26030 * @event OverlayViewDraw
26031 * Fires when OverlayView Draw
26032 * @param {Roo.bootstrap.LocationPicker} this
26034 OverlayViewDraw : true,
26036 * @event OverlayViewOnAdd
26037 * Fires when OverlayView Draw
26038 * @param {Roo.bootstrap.LocationPicker} this
26040 OverlayViewOnAdd : true,
26042 * @event OverlayViewOnRemove
26043 * Fires when OverlayView Draw
26044 * @param {Roo.bootstrap.LocationPicker} this
26046 OverlayViewOnRemove : true,
26048 * @event OverlayViewShow
26049 * Fires when OverlayView Draw
26050 * @param {Roo.bootstrap.LocationPicker} this
26051 * @param {Pixel} cpx
26053 OverlayViewShow : true,
26055 * @event OverlayViewHide
26056 * Fires when OverlayView Draw
26057 * @param {Roo.bootstrap.LocationPicker} this
26059 OverlayViewHide : true,
26061 * @event loadexception
26062 * Fires when load google lib failed.
26063 * @param {Roo.bootstrap.LocationPicker} this
26065 loadexception : true
26070 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26072 gMapContext: false,
26078 mapTypeControl: false,
26079 disableDoubleClickZoom: false,
26081 streetViewControl: false,
26085 enableAutocomplete: false,
26086 enableReverseGeocode: true,
26089 getAutoCreate: function()
26094 cls: 'roo-location-picker'
26100 initEvents: function(ct, position)
26102 if(!this.el.getWidth() || this.isApplied()){
26106 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26111 initial: function()
26113 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26114 this.fireEvent('loadexception', this);
26118 if(!this.mapTypeId){
26119 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26122 this.gMapContext = this.GMapContext();
26124 this.initOverlayView();
26126 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26130 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26131 _this.setPosition(_this.gMapContext.marker.position);
26134 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26135 _this.fireEvent('mapClick', this, event);
26139 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26140 _this.fireEvent('mapRightClick', this, event);
26144 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26145 _this.fireEvent('markerClick', this, event);
26149 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26150 _this.fireEvent('markerRightClick', this, event);
26154 this.setPosition(this.gMapContext.location);
26156 this.fireEvent('initial', this, this.gMapContext.location);
26159 initOverlayView: function()
26163 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26167 _this.fireEvent('OverlayViewDraw', _this);
26172 _this.fireEvent('OverlayViewOnAdd', _this);
26175 onRemove: function()
26177 _this.fireEvent('OverlayViewOnRemove', _this);
26180 show: function(cpx)
26182 _this.fireEvent('OverlayViewShow', _this, cpx);
26187 _this.fireEvent('OverlayViewHide', _this);
26193 fromLatLngToContainerPixel: function(event)
26195 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26198 isApplied: function()
26200 return this.getGmapContext() == false ? false : true;
26203 getGmapContext: function()
26205 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26208 GMapContext: function()
26210 var position = new google.maps.LatLng(this.latitude, this.longitude);
26212 var _map = new google.maps.Map(this.el.dom, {
26215 mapTypeId: this.mapTypeId,
26216 mapTypeControl: this.mapTypeControl,
26217 disableDoubleClickZoom: this.disableDoubleClickZoom,
26218 scrollwheel: this.scrollwheel,
26219 streetViewControl: this.streetViewControl,
26220 locationName: this.locationName,
26221 draggable: this.draggable,
26222 enableAutocomplete: this.enableAutocomplete,
26223 enableReverseGeocode: this.enableReverseGeocode
26226 var _marker = new google.maps.Marker({
26227 position: position,
26229 title: this.markerTitle,
26230 draggable: this.draggable
26237 location: position,
26238 radius: this.radius,
26239 locationName: this.locationName,
26240 addressComponents: {
26241 formatted_address: null,
26242 addressLine1: null,
26243 addressLine2: null,
26245 streetNumber: null,
26249 stateOrProvince: null
26252 domContainer: this.el.dom,
26253 geodecoder: new google.maps.Geocoder()
26257 drawCircle: function(center, radius, options)
26259 if (this.gMapContext.circle != null) {
26260 this.gMapContext.circle.setMap(null);
26264 options = Roo.apply({}, options, {
26265 strokeColor: "#0000FF",
26266 strokeOpacity: .35,
26268 fillColor: "#0000FF",
26272 options.map = this.gMapContext.map;
26273 options.radius = radius;
26274 options.center = center;
26275 this.gMapContext.circle = new google.maps.Circle(options);
26276 return this.gMapContext.circle;
26282 setPosition: function(location)
26284 this.gMapContext.location = location;
26285 this.gMapContext.marker.setPosition(location);
26286 this.gMapContext.map.panTo(location);
26287 this.drawCircle(location, this.gMapContext.radius, {});
26291 if (this.gMapContext.settings.enableReverseGeocode) {
26292 this.gMapContext.geodecoder.geocode({
26293 latLng: this.gMapContext.location
26294 }, function(results, status) {
26296 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26297 _this.gMapContext.locationName = results[0].formatted_address;
26298 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26300 _this.fireEvent('positionchanged', this, location);
26307 this.fireEvent('positionchanged', this, location);
26312 google.maps.event.trigger(this.gMapContext.map, "resize");
26314 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26316 this.fireEvent('resize', this);
26319 setPositionByLatLng: function(latitude, longitude)
26321 this.setPosition(new google.maps.LatLng(latitude, longitude));
26324 getCurrentPosition: function()
26327 latitude: this.gMapContext.location.lat(),
26328 longitude: this.gMapContext.location.lng()
26332 getAddressName: function()
26334 return this.gMapContext.locationName;
26337 getAddressComponents: function()
26339 return this.gMapContext.addressComponents;
26342 address_component_from_google_geocode: function(address_components)
26346 for (var i = 0; i < address_components.length; i++) {
26347 var component = address_components[i];
26348 if (component.types.indexOf("postal_code") >= 0) {
26349 result.postalCode = component.short_name;
26350 } else if (component.types.indexOf("street_number") >= 0) {
26351 result.streetNumber = component.short_name;
26352 } else if (component.types.indexOf("route") >= 0) {
26353 result.streetName = component.short_name;
26354 } else if (component.types.indexOf("neighborhood") >= 0) {
26355 result.city = component.short_name;
26356 } else if (component.types.indexOf("locality") >= 0) {
26357 result.city = component.short_name;
26358 } else if (component.types.indexOf("sublocality") >= 0) {
26359 result.district = component.short_name;
26360 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26361 result.stateOrProvince = component.short_name;
26362 } else if (component.types.indexOf("country") >= 0) {
26363 result.country = component.short_name;
26367 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26368 result.addressLine2 = "";
26372 setZoomLevel: function(zoom)
26374 this.gMapContext.map.setZoom(zoom);
26387 this.fireEvent('show', this);
26398 this.fireEvent('hide', this);
26403 Roo.apply(Roo.bootstrap.LocationPicker, {
26405 OverlayView : function(map, options)
26407 options = options || {};
26421 * @class Roo.bootstrap.Alert
26422 * @extends Roo.bootstrap.Component
26423 * Bootstrap Alert class
26424 * @cfg {String} title The title of alert
26425 * @cfg {String} html The content of alert
26426 * @cfg {String} weight ( success | info | warning | danger )
26427 * @cfg {String} faicon font-awesomeicon
26430 * Create a new alert
26431 * @param {Object} config The config object
26435 Roo.bootstrap.Alert = function(config){
26436 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26440 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26447 getAutoCreate : function()
26456 cls : 'roo-alert-icon'
26461 cls : 'roo-alert-title',
26466 cls : 'roo-alert-text',
26473 cfg.cn[0].cls += ' fa ' + this.faicon;
26477 cfg.cls += ' alert-' + this.weight;
26483 initEvents: function()
26485 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26488 setTitle : function(str)
26490 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26493 setText : function(str)
26495 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26498 setWeight : function(weight)
26501 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26504 this.weight = weight;
26506 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26509 setIcon : function(icon)
26512 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26515 this.faicon = icon;
26517 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26538 * @class Roo.bootstrap.UploadCropbox
26539 * @extends Roo.bootstrap.Component
26540 * Bootstrap UploadCropbox class
26541 * @cfg {String} emptyText show when image has been loaded
26542 * @cfg {String} rotateNotify show when image too small to rotate
26543 * @cfg {Number} errorTimeout default 3000
26544 * @cfg {Number} minWidth default 300
26545 * @cfg {Number} minHeight default 300
26546 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26547 * @cfg {Boolean} isDocument (true|false) default false
26548 * @cfg {String} url action url
26549 * @cfg {String} paramName default 'imageUpload'
26550 * @cfg {String} method default POST
26551 * @cfg {Boolean} loadMask (true|false) default true
26552 * @cfg {Boolean} loadingText default 'Loading...'
26555 * Create a new UploadCropbox
26556 * @param {Object} config The config object
26559 Roo.bootstrap.UploadCropbox = function(config){
26560 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26564 * @event beforeselectfile
26565 * Fire before select file
26566 * @param {Roo.bootstrap.UploadCropbox} this
26568 "beforeselectfile" : true,
26571 * Fire after initEvent
26572 * @param {Roo.bootstrap.UploadCropbox} this
26577 * Fire after initEvent
26578 * @param {Roo.bootstrap.UploadCropbox} this
26579 * @param {String} data
26584 * Fire when preparing the file data
26585 * @param {Roo.bootstrap.UploadCropbox} this
26586 * @param {Object} file
26591 * Fire when get exception
26592 * @param {Roo.bootstrap.UploadCropbox} this
26593 * @param {XMLHttpRequest} xhr
26595 "exception" : true,
26597 * @event beforeloadcanvas
26598 * Fire before load the canvas
26599 * @param {Roo.bootstrap.UploadCropbox} this
26600 * @param {String} src
26602 "beforeloadcanvas" : true,
26605 * Fire when trash image
26606 * @param {Roo.bootstrap.UploadCropbox} this
26611 * Fire when download the image
26612 * @param {Roo.bootstrap.UploadCropbox} this
26616 * @event footerbuttonclick
26617 * Fire when footerbuttonclick
26618 * @param {Roo.bootstrap.UploadCropbox} this
26619 * @param {String} type
26621 "footerbuttonclick" : true,
26625 * @param {Roo.bootstrap.UploadCropbox} this
26630 * Fire when rotate the image
26631 * @param {Roo.bootstrap.UploadCropbox} this
26632 * @param {String} pos
26637 * Fire when inspect the file
26638 * @param {Roo.bootstrap.UploadCropbox} this
26639 * @param {Object} file
26644 * Fire when xhr upload the file
26645 * @param {Roo.bootstrap.UploadCropbox} this
26646 * @param {Object} data
26651 * Fire when arrange the file data
26652 * @param {Roo.bootstrap.UploadCropbox} this
26653 * @param {Object} formData
26658 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26661 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26663 emptyText : 'Click to upload image',
26664 rotateNotify : 'Image is too small to rotate',
26665 errorTimeout : 3000,
26679 cropType : 'image/jpeg',
26681 canvasLoaded : false,
26682 isDocument : false,
26684 paramName : 'imageUpload',
26686 loadingText : 'Loading...',
26689 getAutoCreate : function()
26693 cls : 'roo-upload-cropbox',
26697 cls : 'roo-upload-cropbox-selector',
26702 cls : 'roo-upload-cropbox-body',
26703 style : 'cursor:pointer',
26707 cls : 'roo-upload-cropbox-preview'
26711 cls : 'roo-upload-cropbox-thumb'
26715 cls : 'roo-upload-cropbox-empty-notify',
26716 html : this.emptyText
26720 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26721 html : this.rotateNotify
26727 cls : 'roo-upload-cropbox-footer',
26730 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26740 onRender : function(ct, position)
26742 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26744 if (this.buttons.length) {
26746 Roo.each(this.buttons, function(bb) {
26748 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26750 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26756 this.maskEl = this.el;
26760 initEvents : function()
26762 this.urlAPI = (window.createObjectURL && window) ||
26763 (window.URL && URL.revokeObjectURL && URL) ||
26764 (window.webkitURL && webkitURL);
26766 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26767 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26769 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26770 this.selectorEl.hide();
26772 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26773 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26775 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26776 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26777 this.thumbEl.hide();
26779 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26780 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26782 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26783 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26784 this.errorEl.hide();
26786 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26787 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26788 this.footerEl.hide();
26790 this.setThumbBoxSize();
26796 this.fireEvent('initial', this);
26803 window.addEventListener("resize", function() { _this.resize(); } );
26805 this.bodyEl.on('click', this.beforeSelectFile, this);
26808 this.bodyEl.on('touchstart', this.onTouchStart, this);
26809 this.bodyEl.on('touchmove', this.onTouchMove, this);
26810 this.bodyEl.on('touchend', this.onTouchEnd, this);
26814 this.bodyEl.on('mousedown', this.onMouseDown, this);
26815 this.bodyEl.on('mousemove', this.onMouseMove, this);
26816 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26817 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26818 Roo.get(document).on('mouseup', this.onMouseUp, this);
26821 this.selectorEl.on('change', this.onFileSelected, this);
26827 this.baseScale = 1;
26829 this.baseRotate = 1;
26830 this.dragable = false;
26831 this.pinching = false;
26834 this.cropData = false;
26835 this.notifyEl.dom.innerHTML = this.emptyText;
26837 this.selectorEl.dom.value = '';
26841 resize : function()
26843 if(this.fireEvent('resize', this) != false){
26844 this.setThumbBoxPosition();
26845 this.setCanvasPosition();
26849 onFooterButtonClick : function(e, el, o, type)
26852 case 'rotate-left' :
26853 this.onRotateLeft(e);
26855 case 'rotate-right' :
26856 this.onRotateRight(e);
26859 this.beforeSelectFile(e);
26874 this.fireEvent('footerbuttonclick', this, type);
26877 beforeSelectFile : function(e)
26879 e.preventDefault();
26881 if(this.fireEvent('beforeselectfile', this) != false){
26882 this.selectorEl.dom.click();
26886 onFileSelected : function(e)
26888 e.preventDefault();
26890 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26894 var file = this.selectorEl.dom.files[0];
26896 if(this.fireEvent('inspect', this, file) != false){
26897 this.prepare(file);
26902 trash : function(e)
26904 this.fireEvent('trash', this);
26907 download : function(e)
26909 this.fireEvent('download', this);
26912 loadCanvas : function(src)
26914 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26918 this.imageEl = document.createElement('img');
26922 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26924 this.imageEl.src = src;
26928 onLoadCanvas : function()
26930 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26931 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26933 this.bodyEl.un('click', this.beforeSelectFile, this);
26935 this.notifyEl.hide();
26936 this.thumbEl.show();
26937 this.footerEl.show();
26939 this.baseRotateLevel();
26941 if(this.isDocument){
26942 this.setThumbBoxSize();
26945 this.setThumbBoxPosition();
26947 this.baseScaleLevel();
26953 this.canvasLoaded = true;
26956 this.maskEl.unmask();
26961 setCanvasPosition : function()
26963 if(!this.canvasEl){
26967 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26968 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26970 this.previewEl.setLeft(pw);
26971 this.previewEl.setTop(ph);
26975 onMouseDown : function(e)
26979 this.dragable = true;
26980 this.pinching = false;
26982 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26983 this.dragable = false;
26987 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26988 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26992 onMouseMove : function(e)
26996 if(!this.canvasLoaded){
27000 if (!this.dragable){
27004 var minX = Math.ceil(this.thumbEl.getLeft(true));
27005 var minY = Math.ceil(this.thumbEl.getTop(true));
27007 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27008 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27010 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27011 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27013 x = x - this.mouseX;
27014 y = y - this.mouseY;
27016 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27017 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27019 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27020 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27022 this.previewEl.setLeft(bgX);
27023 this.previewEl.setTop(bgY);
27025 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27026 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27029 onMouseUp : function(e)
27033 this.dragable = false;
27036 onMouseWheel : function(e)
27040 this.startScale = this.scale;
27042 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27044 if(!this.zoomable()){
27045 this.scale = this.startScale;
27054 zoomable : function()
27056 var minScale = this.thumbEl.getWidth() / this.minWidth;
27058 if(this.minWidth < this.minHeight){
27059 minScale = this.thumbEl.getHeight() / this.minHeight;
27062 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27063 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27067 (this.rotate == 0 || this.rotate == 180) &&
27069 width > this.imageEl.OriginWidth ||
27070 height > this.imageEl.OriginHeight ||
27071 (width < this.minWidth && height < this.minHeight)
27079 (this.rotate == 90 || this.rotate == 270) &&
27081 width > this.imageEl.OriginWidth ||
27082 height > this.imageEl.OriginHeight ||
27083 (width < this.minHeight && height < this.minWidth)
27090 !this.isDocument &&
27091 (this.rotate == 0 || this.rotate == 180) &&
27093 width < this.minWidth ||
27094 width > this.imageEl.OriginWidth ||
27095 height < this.minHeight ||
27096 height > this.imageEl.OriginHeight
27103 !this.isDocument &&
27104 (this.rotate == 90 || this.rotate == 270) &&
27106 width < this.minHeight ||
27107 width > this.imageEl.OriginWidth ||
27108 height < this.minWidth ||
27109 height > this.imageEl.OriginHeight
27119 onRotateLeft : function(e)
27121 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27123 var minScale = this.thumbEl.getWidth() / this.minWidth;
27125 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27126 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27128 this.startScale = this.scale;
27130 while (this.getScaleLevel() < minScale){
27132 this.scale = this.scale + 1;
27134 if(!this.zoomable()){
27139 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27140 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27145 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27152 this.scale = this.startScale;
27154 this.onRotateFail();
27159 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27161 if(this.isDocument){
27162 this.setThumbBoxSize();
27163 this.setThumbBoxPosition();
27164 this.setCanvasPosition();
27169 this.fireEvent('rotate', this, 'left');
27173 onRotateRight : function(e)
27175 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27177 var minScale = this.thumbEl.getWidth() / this.minWidth;
27179 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27180 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27182 this.startScale = this.scale;
27184 while (this.getScaleLevel() < minScale){
27186 this.scale = this.scale + 1;
27188 if(!this.zoomable()){
27193 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27194 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27199 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27206 this.scale = this.startScale;
27208 this.onRotateFail();
27213 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27215 if(this.isDocument){
27216 this.setThumbBoxSize();
27217 this.setThumbBoxPosition();
27218 this.setCanvasPosition();
27223 this.fireEvent('rotate', this, 'right');
27226 onRotateFail : function()
27228 this.errorEl.show(true);
27232 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27237 this.previewEl.dom.innerHTML = '';
27239 var canvasEl = document.createElement("canvas");
27241 var contextEl = canvasEl.getContext("2d");
27243 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27244 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27245 var center = this.imageEl.OriginWidth / 2;
27247 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27248 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27249 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27250 center = this.imageEl.OriginHeight / 2;
27253 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27255 contextEl.translate(center, center);
27256 contextEl.rotate(this.rotate * Math.PI / 180);
27258 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27260 this.canvasEl = document.createElement("canvas");
27262 this.contextEl = this.canvasEl.getContext("2d");
27264 switch (this.rotate) {
27267 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27268 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27270 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27275 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27276 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27278 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27279 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);
27283 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27288 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27289 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27291 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27292 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);
27296 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);
27301 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27302 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27304 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27305 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27309 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);
27316 this.previewEl.appendChild(this.canvasEl);
27318 this.setCanvasPosition();
27323 if(!this.canvasLoaded){
27327 var imageCanvas = document.createElement("canvas");
27329 var imageContext = imageCanvas.getContext("2d");
27331 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27332 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27334 var center = imageCanvas.width / 2;
27336 imageContext.translate(center, center);
27338 imageContext.rotate(this.rotate * Math.PI / 180);
27340 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27342 var canvas = document.createElement("canvas");
27344 var context = canvas.getContext("2d");
27346 canvas.width = this.minWidth;
27347 canvas.height = this.minHeight;
27349 switch (this.rotate) {
27352 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27353 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27355 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27356 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27358 var targetWidth = this.minWidth - 2 * x;
27359 var targetHeight = this.minHeight - 2 * y;
27363 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27364 scale = targetWidth / width;
27367 if(x > 0 && y == 0){
27368 scale = targetHeight / height;
27371 if(x > 0 && y > 0){
27372 scale = targetWidth / width;
27374 if(width < height){
27375 scale = targetHeight / height;
27379 context.scale(scale, scale);
27381 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27382 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27384 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27385 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27387 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27392 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27393 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27395 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27396 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27398 var targetWidth = this.minWidth - 2 * x;
27399 var targetHeight = this.minHeight - 2 * y;
27403 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27404 scale = targetWidth / width;
27407 if(x > 0 && y == 0){
27408 scale = targetHeight / height;
27411 if(x > 0 && y > 0){
27412 scale = targetWidth / width;
27414 if(width < height){
27415 scale = targetHeight / height;
27419 context.scale(scale, scale);
27421 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27422 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27424 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27425 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27427 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27429 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27434 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27435 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27437 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27438 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27440 var targetWidth = this.minWidth - 2 * x;
27441 var targetHeight = this.minHeight - 2 * y;
27445 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27446 scale = targetWidth / width;
27449 if(x > 0 && y == 0){
27450 scale = targetHeight / height;
27453 if(x > 0 && y > 0){
27454 scale = targetWidth / width;
27456 if(width < height){
27457 scale = targetHeight / height;
27461 context.scale(scale, scale);
27463 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27464 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27466 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27467 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27469 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27470 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27472 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27477 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27478 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27480 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27481 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27483 var targetWidth = this.minWidth - 2 * x;
27484 var targetHeight = this.minHeight - 2 * y;
27488 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27489 scale = targetWidth / width;
27492 if(x > 0 && y == 0){
27493 scale = targetHeight / height;
27496 if(x > 0 && y > 0){
27497 scale = targetWidth / width;
27499 if(width < height){
27500 scale = targetHeight / height;
27504 context.scale(scale, scale);
27506 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27507 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27509 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27510 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27512 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27514 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27521 this.cropData = canvas.toDataURL(this.cropType);
27523 if(this.fireEvent('crop', this, this.cropData) !== false){
27524 this.process(this.file, this.cropData);
27531 setThumbBoxSize : function()
27535 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27536 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27537 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27539 this.minWidth = width;
27540 this.minHeight = height;
27542 if(this.rotate == 90 || this.rotate == 270){
27543 this.minWidth = height;
27544 this.minHeight = width;
27549 width = Math.ceil(this.minWidth * height / this.minHeight);
27551 if(this.minWidth > this.minHeight){
27553 height = Math.ceil(this.minHeight * width / this.minWidth);
27556 this.thumbEl.setStyle({
27557 width : width + 'px',
27558 height : height + 'px'
27565 setThumbBoxPosition : function()
27567 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27568 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27570 this.thumbEl.setLeft(x);
27571 this.thumbEl.setTop(y);
27575 baseRotateLevel : function()
27577 this.baseRotate = 1;
27580 typeof(this.exif) != 'undefined' &&
27581 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27582 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27584 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27587 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27591 baseScaleLevel : function()
27595 if(this.isDocument){
27597 if(this.baseRotate == 6 || this.baseRotate == 8){
27599 height = this.thumbEl.getHeight();
27600 this.baseScale = height / this.imageEl.OriginWidth;
27602 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27603 width = this.thumbEl.getWidth();
27604 this.baseScale = width / this.imageEl.OriginHeight;
27610 height = this.thumbEl.getHeight();
27611 this.baseScale = height / this.imageEl.OriginHeight;
27613 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27614 width = this.thumbEl.getWidth();
27615 this.baseScale = width / this.imageEl.OriginWidth;
27621 if(this.baseRotate == 6 || this.baseRotate == 8){
27623 width = this.thumbEl.getHeight();
27624 this.baseScale = width / this.imageEl.OriginHeight;
27626 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27627 height = this.thumbEl.getWidth();
27628 this.baseScale = height / this.imageEl.OriginHeight;
27631 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27632 height = this.thumbEl.getWidth();
27633 this.baseScale = height / this.imageEl.OriginHeight;
27635 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27636 width = this.thumbEl.getHeight();
27637 this.baseScale = width / this.imageEl.OriginWidth;
27644 width = this.thumbEl.getWidth();
27645 this.baseScale = width / this.imageEl.OriginWidth;
27647 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27648 height = this.thumbEl.getHeight();
27649 this.baseScale = height / this.imageEl.OriginHeight;
27652 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27654 height = this.thumbEl.getHeight();
27655 this.baseScale = height / this.imageEl.OriginHeight;
27657 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27658 width = this.thumbEl.getWidth();
27659 this.baseScale = width / this.imageEl.OriginWidth;
27667 getScaleLevel : function()
27669 return this.baseScale * Math.pow(1.1, this.scale);
27672 onTouchStart : function(e)
27674 if(!this.canvasLoaded){
27675 this.beforeSelectFile(e);
27679 var touches = e.browserEvent.touches;
27685 if(touches.length == 1){
27686 this.onMouseDown(e);
27690 if(touches.length != 2){
27696 for(var i = 0, finger; finger = touches[i]; i++){
27697 coords.push(finger.pageX, finger.pageY);
27700 var x = Math.pow(coords[0] - coords[2], 2);
27701 var y = Math.pow(coords[1] - coords[3], 2);
27703 this.startDistance = Math.sqrt(x + y);
27705 this.startScale = this.scale;
27707 this.pinching = true;
27708 this.dragable = false;
27712 onTouchMove : function(e)
27714 if(!this.pinching && !this.dragable){
27718 var touches = e.browserEvent.touches;
27725 this.onMouseMove(e);
27731 for(var i = 0, finger; finger = touches[i]; i++){
27732 coords.push(finger.pageX, finger.pageY);
27735 var x = Math.pow(coords[0] - coords[2], 2);
27736 var y = Math.pow(coords[1] - coords[3], 2);
27738 this.endDistance = Math.sqrt(x + y);
27740 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27742 if(!this.zoomable()){
27743 this.scale = this.startScale;
27751 onTouchEnd : function(e)
27753 this.pinching = false;
27754 this.dragable = false;
27758 process : function(file, crop)
27761 this.maskEl.mask(this.loadingText);
27764 this.xhr = new XMLHttpRequest();
27766 file.xhr = this.xhr;
27768 this.xhr.open(this.method, this.url, true);
27771 "Accept": "application/json",
27772 "Cache-Control": "no-cache",
27773 "X-Requested-With": "XMLHttpRequest"
27776 for (var headerName in headers) {
27777 var headerValue = headers[headerName];
27779 this.xhr.setRequestHeader(headerName, headerValue);
27785 this.xhr.onload = function()
27787 _this.xhrOnLoad(_this.xhr);
27790 this.xhr.onerror = function()
27792 _this.xhrOnError(_this.xhr);
27795 var formData = new FormData();
27797 formData.append('returnHTML', 'NO');
27800 formData.append('crop', crop);
27803 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27804 formData.append(this.paramName, file, file.name);
27807 if(typeof(file.filename) != 'undefined'){
27808 formData.append('filename', file.filename);
27811 if(typeof(file.mimetype) != 'undefined'){
27812 formData.append('mimetype', file.mimetype);
27815 if(this.fireEvent('arrange', this, formData) != false){
27816 this.xhr.send(formData);
27820 xhrOnLoad : function(xhr)
27823 this.maskEl.unmask();
27826 if (xhr.readyState !== 4) {
27827 this.fireEvent('exception', this, xhr);
27831 var response = Roo.decode(xhr.responseText);
27833 if(!response.success){
27834 this.fireEvent('exception', this, xhr);
27838 var response = Roo.decode(xhr.responseText);
27840 this.fireEvent('upload', this, response);
27844 xhrOnError : function()
27847 this.maskEl.unmask();
27850 Roo.log('xhr on error');
27852 var response = Roo.decode(xhr.responseText);
27858 prepare : function(file)
27861 this.maskEl.mask(this.loadingText);
27867 if(typeof(file) === 'string'){
27868 this.loadCanvas(file);
27872 if(!file || !this.urlAPI){
27877 this.cropType = file.type;
27881 if(this.fireEvent('prepare', this, this.file) != false){
27883 var reader = new FileReader();
27885 reader.onload = function (e) {
27886 if (e.target.error) {
27887 Roo.log(e.target.error);
27891 var buffer = e.target.result,
27892 dataView = new DataView(buffer),
27894 maxOffset = dataView.byteLength - 4,
27898 if (dataView.getUint16(0) === 0xffd8) {
27899 while (offset < maxOffset) {
27900 markerBytes = dataView.getUint16(offset);
27902 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27903 markerLength = dataView.getUint16(offset + 2) + 2;
27904 if (offset + markerLength > dataView.byteLength) {
27905 Roo.log('Invalid meta data: Invalid segment size.');
27909 if(markerBytes == 0xffe1){
27910 _this.parseExifData(
27917 offset += markerLength;
27927 var url = _this.urlAPI.createObjectURL(_this.file);
27929 _this.loadCanvas(url);
27934 reader.readAsArrayBuffer(this.file);
27940 parseExifData : function(dataView, offset, length)
27942 var tiffOffset = offset + 10,
27946 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27947 // No Exif data, might be XMP data instead
27951 // Check for the ASCII code for "Exif" (0x45786966):
27952 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27953 // No Exif data, might be XMP data instead
27956 if (tiffOffset + 8 > dataView.byteLength) {
27957 Roo.log('Invalid Exif data: Invalid segment size.');
27960 // Check for the two null bytes:
27961 if (dataView.getUint16(offset + 8) !== 0x0000) {
27962 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27965 // Check the byte alignment:
27966 switch (dataView.getUint16(tiffOffset)) {
27968 littleEndian = true;
27971 littleEndian = false;
27974 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27977 // Check for the TIFF tag marker (0x002A):
27978 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27979 Roo.log('Invalid Exif data: Missing TIFF marker.');
27982 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27983 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27985 this.parseExifTags(
27988 tiffOffset + dirOffset,
27993 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27998 if (dirOffset + 6 > dataView.byteLength) {
27999 Roo.log('Invalid Exif data: Invalid directory offset.');
28002 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28003 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28004 if (dirEndOffset + 4 > dataView.byteLength) {
28005 Roo.log('Invalid Exif data: Invalid directory size.');
28008 for (i = 0; i < tagsNumber; i += 1) {
28012 dirOffset + 2 + 12 * i, // tag offset
28016 // Return the offset to the next directory:
28017 return dataView.getUint32(dirEndOffset, littleEndian);
28020 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28022 var tag = dataView.getUint16(offset, littleEndian);
28024 this.exif[tag] = this.getExifValue(
28028 dataView.getUint16(offset + 2, littleEndian), // tag type
28029 dataView.getUint32(offset + 4, littleEndian), // tag length
28034 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28036 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28045 Roo.log('Invalid Exif data: Invalid tag type.');
28049 tagSize = tagType.size * length;
28050 // Determine if the value is contained in the dataOffset bytes,
28051 // or if the value at the dataOffset is a pointer to the actual data:
28052 dataOffset = tagSize > 4 ?
28053 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28054 if (dataOffset + tagSize > dataView.byteLength) {
28055 Roo.log('Invalid Exif data: Invalid data offset.');
28058 if (length === 1) {
28059 return tagType.getValue(dataView, dataOffset, littleEndian);
28062 for (i = 0; i < length; i += 1) {
28063 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28066 if (tagType.ascii) {
28068 // Concatenate the chars:
28069 for (i = 0; i < values.length; i += 1) {
28071 // Ignore the terminating NULL byte(s):
28072 if (c === '\u0000') {
28084 Roo.apply(Roo.bootstrap.UploadCropbox, {
28086 'Orientation': 0x0112
28090 1: 0, //'top-left',
28092 3: 180, //'bottom-right',
28093 // 4: 'bottom-left',
28095 6: 90, //'right-top',
28096 // 7: 'right-bottom',
28097 8: 270 //'left-bottom'
28101 // byte, 8-bit unsigned int:
28103 getValue: function (dataView, dataOffset) {
28104 return dataView.getUint8(dataOffset);
28108 // ascii, 8-bit byte:
28110 getValue: function (dataView, dataOffset) {
28111 return String.fromCharCode(dataView.getUint8(dataOffset));
28116 // short, 16 bit int:
28118 getValue: function (dataView, dataOffset, littleEndian) {
28119 return dataView.getUint16(dataOffset, littleEndian);
28123 // long, 32 bit int:
28125 getValue: function (dataView, dataOffset, littleEndian) {
28126 return dataView.getUint32(dataOffset, littleEndian);
28130 // rational = two long values, first is numerator, second is denominator:
28132 getValue: function (dataView, dataOffset, littleEndian) {
28133 return dataView.getUint32(dataOffset, littleEndian) /
28134 dataView.getUint32(dataOffset + 4, littleEndian);
28138 // slong, 32 bit signed int:
28140 getValue: function (dataView, dataOffset, littleEndian) {
28141 return dataView.getInt32(dataOffset, littleEndian);
28145 // srational, two slongs, first is numerator, second is denominator:
28147 getValue: function (dataView, dataOffset, littleEndian) {
28148 return dataView.getInt32(dataOffset, littleEndian) /
28149 dataView.getInt32(dataOffset + 4, littleEndian);
28159 cls : 'btn-group roo-upload-cropbox-rotate-left',
28160 action : 'rotate-left',
28164 cls : 'btn btn-default',
28165 html : '<i class="fa fa-undo"></i>'
28171 cls : 'btn-group roo-upload-cropbox-picture',
28172 action : 'picture',
28176 cls : 'btn btn-default',
28177 html : '<i class="fa fa-picture-o"></i>'
28183 cls : 'btn-group roo-upload-cropbox-rotate-right',
28184 action : 'rotate-right',
28188 cls : 'btn btn-default',
28189 html : '<i class="fa fa-repeat"></i>'
28197 cls : 'btn-group roo-upload-cropbox-rotate-left',
28198 action : 'rotate-left',
28202 cls : 'btn btn-default',
28203 html : '<i class="fa fa-undo"></i>'
28209 cls : 'btn-group roo-upload-cropbox-download',
28210 action : 'download',
28214 cls : 'btn btn-default',
28215 html : '<i class="fa fa-download"></i>'
28221 cls : 'btn-group roo-upload-cropbox-crop',
28226 cls : 'btn btn-default',
28227 html : '<i class="fa fa-crop"></i>'
28233 cls : 'btn-group roo-upload-cropbox-trash',
28238 cls : 'btn btn-default',
28239 html : '<i class="fa fa-trash"></i>'
28245 cls : 'btn-group roo-upload-cropbox-rotate-right',
28246 action : 'rotate-right',
28250 cls : 'btn btn-default',
28251 html : '<i class="fa fa-repeat"></i>'
28259 cls : 'btn-group roo-upload-cropbox-rotate-left',
28260 action : 'rotate-left',
28264 cls : 'btn btn-default',
28265 html : '<i class="fa fa-undo"></i>'
28271 cls : 'btn-group roo-upload-cropbox-rotate-right',
28272 action : 'rotate-right',
28276 cls : 'btn btn-default',
28277 html : '<i class="fa fa-repeat"></i>'
28290 * @class Roo.bootstrap.DocumentManager
28291 * @extends Roo.bootstrap.Component
28292 * Bootstrap DocumentManager class
28293 * @cfg {String} paramName default 'imageUpload'
28294 * @cfg {String} toolTipName default 'filename'
28295 * @cfg {String} method default POST
28296 * @cfg {String} url action url
28297 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28298 * @cfg {Boolean} multiple multiple upload default true
28299 * @cfg {Number} thumbSize default 300
28300 * @cfg {String} fieldLabel
28301 * @cfg {Number} labelWidth default 4
28302 * @cfg {String} labelAlign (left|top) default left
28303 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28304 * @cfg {Number} labellg set the width of label (1-12)
28305 * @cfg {Number} labelmd set the width of label (1-12)
28306 * @cfg {Number} labelsm set the width of label (1-12)
28307 * @cfg {Number} labelxs set the width of label (1-12)
28310 * Create a new DocumentManager
28311 * @param {Object} config The config object
28314 Roo.bootstrap.DocumentManager = function(config){
28315 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28318 this.delegates = [];
28323 * Fire when initial the DocumentManager
28324 * @param {Roo.bootstrap.DocumentManager} this
28329 * inspect selected file
28330 * @param {Roo.bootstrap.DocumentManager} this
28331 * @param {File} file
28336 * Fire when xhr load exception
28337 * @param {Roo.bootstrap.DocumentManager} this
28338 * @param {XMLHttpRequest} xhr
28340 "exception" : true,
28342 * @event afterupload
28343 * Fire when xhr load exception
28344 * @param {Roo.bootstrap.DocumentManager} this
28345 * @param {XMLHttpRequest} xhr
28347 "afterupload" : true,
28350 * prepare the form data
28351 * @param {Roo.bootstrap.DocumentManager} this
28352 * @param {Object} formData
28357 * Fire when remove the file
28358 * @param {Roo.bootstrap.DocumentManager} this
28359 * @param {Object} file
28364 * Fire after refresh the file
28365 * @param {Roo.bootstrap.DocumentManager} this
28370 * Fire after click the image
28371 * @param {Roo.bootstrap.DocumentManager} this
28372 * @param {Object} file
28377 * Fire when upload a image and editable set to true
28378 * @param {Roo.bootstrap.DocumentManager} this
28379 * @param {Object} file
28383 * @event beforeselectfile
28384 * Fire before select file
28385 * @param {Roo.bootstrap.DocumentManager} this
28387 "beforeselectfile" : true,
28390 * Fire before process file
28391 * @param {Roo.bootstrap.DocumentManager} this
28392 * @param {Object} file
28399 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28408 paramName : 'imageUpload',
28409 toolTipName : 'filename',
28412 labelAlign : 'left',
28422 getAutoCreate : function()
28424 var managerWidget = {
28426 cls : 'roo-document-manager',
28430 cls : 'roo-document-manager-selector',
28435 cls : 'roo-document-manager-uploader',
28439 cls : 'roo-document-manager-upload-btn',
28440 html : '<i class="fa fa-plus"></i>'
28451 cls : 'column col-md-12',
28456 if(this.fieldLabel.length){
28461 cls : 'column col-md-12',
28462 html : this.fieldLabel
28466 cls : 'column col-md-12',
28471 if(this.labelAlign == 'left'){
28476 html : this.fieldLabel
28485 if(this.labelWidth > 12){
28486 content[0].style = "width: " + this.labelWidth + 'px';
28489 if(this.labelWidth < 13 && this.labelmd == 0){
28490 this.labelmd = this.labelWidth;
28493 if(this.labellg > 0){
28494 content[0].cls += ' col-lg-' + this.labellg;
28495 content[1].cls += ' col-lg-' + (12 - this.labellg);
28498 if(this.labelmd > 0){
28499 content[0].cls += ' col-md-' + this.labelmd;
28500 content[1].cls += ' col-md-' + (12 - this.labelmd);
28503 if(this.labelsm > 0){
28504 content[0].cls += ' col-sm-' + this.labelsm;
28505 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28508 if(this.labelxs > 0){
28509 content[0].cls += ' col-xs-' + this.labelxs;
28510 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28518 cls : 'row clearfix',
28526 initEvents : function()
28528 this.managerEl = this.el.select('.roo-document-manager', true).first();
28529 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28531 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28532 this.selectorEl.hide();
28535 this.selectorEl.attr('multiple', 'multiple');
28538 this.selectorEl.on('change', this.onFileSelected, this);
28540 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28541 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28543 this.uploader.on('click', this.onUploaderClick, this);
28545 this.renderProgressDialog();
28549 window.addEventListener("resize", function() { _this.refresh(); } );
28551 this.fireEvent('initial', this);
28554 renderProgressDialog : function()
28558 this.progressDialog = new Roo.bootstrap.Modal({
28559 cls : 'roo-document-manager-progress-dialog',
28560 allow_close : false,
28570 btnclick : function() {
28571 _this.uploadCancel();
28577 this.progressDialog.render(Roo.get(document.body));
28579 this.progress = new Roo.bootstrap.Progress({
28580 cls : 'roo-document-manager-progress',
28585 this.progress.render(this.progressDialog.getChildContainer());
28587 this.progressBar = new Roo.bootstrap.ProgressBar({
28588 cls : 'roo-document-manager-progress-bar',
28591 aria_valuemax : 12,
28595 this.progressBar.render(this.progress.getChildContainer());
28598 onUploaderClick : function(e)
28600 e.preventDefault();
28602 if(this.fireEvent('beforeselectfile', this) != false){
28603 this.selectorEl.dom.click();
28608 onFileSelected : function(e)
28610 e.preventDefault();
28612 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28616 Roo.each(this.selectorEl.dom.files, function(file){
28617 if(this.fireEvent('inspect', this, file) != false){
28618 this.files.push(file);
28628 this.selectorEl.dom.value = '';
28630 if(!this.files.length){
28634 if(this.boxes > 0 && this.files.length > this.boxes){
28635 this.files = this.files.slice(0, this.boxes);
28638 this.uploader.show();
28640 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28641 this.uploader.hide();
28650 Roo.each(this.files, function(file){
28652 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28653 var f = this.renderPreview(file);
28658 if(file.type.indexOf('image') != -1){
28659 this.delegates.push(
28661 _this.process(file);
28662 }).createDelegate(this)
28670 _this.process(file);
28671 }).createDelegate(this)
28676 this.files = files;
28678 this.delegates = this.delegates.concat(docs);
28680 if(!this.delegates.length){
28685 this.progressBar.aria_valuemax = this.delegates.length;
28692 arrange : function()
28694 if(!this.delegates.length){
28695 this.progressDialog.hide();
28700 var delegate = this.delegates.shift();
28702 this.progressDialog.show();
28704 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28706 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28711 refresh : function()
28713 this.uploader.show();
28715 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28716 this.uploader.hide();
28719 Roo.isTouch ? this.closable(false) : this.closable(true);
28721 this.fireEvent('refresh', this);
28724 onRemove : function(e, el, o)
28726 e.preventDefault();
28728 this.fireEvent('remove', this, o);
28732 remove : function(o)
28736 Roo.each(this.files, function(file){
28737 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28746 this.files = files;
28753 Roo.each(this.files, function(file){
28758 file.target.remove();
28767 onClick : function(e, el, o)
28769 e.preventDefault();
28771 this.fireEvent('click', this, o);
28775 closable : function(closable)
28777 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28779 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28791 xhrOnLoad : function(xhr)
28793 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28797 if (xhr.readyState !== 4) {
28799 this.fireEvent('exception', this, xhr);
28803 var response = Roo.decode(xhr.responseText);
28805 if(!response.success){
28807 this.fireEvent('exception', this, xhr);
28811 var file = this.renderPreview(response.data);
28813 this.files.push(file);
28817 this.fireEvent('afterupload', this, xhr);
28821 xhrOnError : function(xhr)
28823 Roo.log('xhr on error');
28825 var response = Roo.decode(xhr.responseText);
28832 process : function(file)
28834 if(this.fireEvent('process', this, file) !== false){
28835 if(this.editable && file.type.indexOf('image') != -1){
28836 this.fireEvent('edit', this, file);
28840 this.uploadStart(file, false);
28847 uploadStart : function(file, crop)
28849 this.xhr = new XMLHttpRequest();
28851 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28856 file.xhr = this.xhr;
28858 this.managerEl.createChild({
28860 cls : 'roo-document-manager-loading',
28864 tooltip : file.name,
28865 cls : 'roo-document-manager-thumb',
28866 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28872 this.xhr.open(this.method, this.url, true);
28875 "Accept": "application/json",
28876 "Cache-Control": "no-cache",
28877 "X-Requested-With": "XMLHttpRequest"
28880 for (var headerName in headers) {
28881 var headerValue = headers[headerName];
28883 this.xhr.setRequestHeader(headerName, headerValue);
28889 this.xhr.onload = function()
28891 _this.xhrOnLoad(_this.xhr);
28894 this.xhr.onerror = function()
28896 _this.xhrOnError(_this.xhr);
28899 var formData = new FormData();
28901 formData.append('returnHTML', 'NO');
28904 formData.append('crop', crop);
28907 formData.append(this.paramName, file, file.name);
28914 if(this.fireEvent('prepare', this, formData, options) != false){
28916 if(options.manually){
28920 this.xhr.send(formData);
28924 this.uploadCancel();
28927 uploadCancel : function()
28933 this.delegates = [];
28935 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28942 renderPreview : function(file)
28944 if(typeof(file.target) != 'undefined' && file.target){
28948 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
28950 var previewEl = this.managerEl.createChild({
28952 cls : 'roo-document-manager-preview',
28956 tooltip : file[this.toolTipName],
28957 cls : 'roo-document-manager-thumb',
28958 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
28963 html : '<i class="fa fa-times-circle"></i>'
28968 var close = previewEl.select('button.close', true).first();
28970 close.on('click', this.onRemove, this, file);
28972 file.target = previewEl;
28974 var image = previewEl.select('img', true).first();
28978 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28980 image.on('click', this.onClick, this, file);
28986 onPreviewLoad : function(file, image)
28988 if(typeof(file.target) == 'undefined' || !file.target){
28992 var width = image.dom.naturalWidth || image.dom.width;
28993 var height = image.dom.naturalHeight || image.dom.height;
28995 if(width > height){
28996 file.target.addClass('wide');
29000 file.target.addClass('tall');
29005 uploadFromSource : function(file, crop)
29007 this.xhr = new XMLHttpRequest();
29009 this.managerEl.createChild({
29011 cls : 'roo-document-manager-loading',
29015 tooltip : file.name,
29016 cls : 'roo-document-manager-thumb',
29017 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29023 this.xhr.open(this.method, this.url, true);
29026 "Accept": "application/json",
29027 "Cache-Control": "no-cache",
29028 "X-Requested-With": "XMLHttpRequest"
29031 for (var headerName in headers) {
29032 var headerValue = headers[headerName];
29034 this.xhr.setRequestHeader(headerName, headerValue);
29040 this.xhr.onload = function()
29042 _this.xhrOnLoad(_this.xhr);
29045 this.xhr.onerror = function()
29047 _this.xhrOnError(_this.xhr);
29050 var formData = new FormData();
29052 formData.append('returnHTML', 'NO');
29054 formData.append('crop', crop);
29056 if(typeof(file.filename) != 'undefined'){
29057 formData.append('filename', file.filename);
29060 if(typeof(file.mimetype) != 'undefined'){
29061 formData.append('mimetype', file.mimetype);
29066 if(this.fireEvent('prepare', this, formData) != false){
29067 this.xhr.send(formData);
29077 * @class Roo.bootstrap.DocumentViewer
29078 * @extends Roo.bootstrap.Component
29079 * Bootstrap DocumentViewer class
29080 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29081 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29084 * Create a new DocumentViewer
29085 * @param {Object} config The config object
29088 Roo.bootstrap.DocumentViewer = function(config){
29089 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29094 * Fire after initEvent
29095 * @param {Roo.bootstrap.DocumentViewer} this
29101 * @param {Roo.bootstrap.DocumentViewer} this
29106 * Fire after download button
29107 * @param {Roo.bootstrap.DocumentViewer} this
29112 * Fire after trash button
29113 * @param {Roo.bootstrap.DocumentViewer} this
29120 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29122 showDownload : true,
29126 getAutoCreate : function()
29130 cls : 'roo-document-viewer',
29134 cls : 'roo-document-viewer-body',
29138 cls : 'roo-document-viewer-thumb',
29142 cls : 'roo-document-viewer-image'
29150 cls : 'roo-document-viewer-footer',
29153 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29157 cls : 'btn-group roo-document-viewer-download',
29161 cls : 'btn btn-default',
29162 html : '<i class="fa fa-download"></i>'
29168 cls : 'btn-group roo-document-viewer-trash',
29172 cls : 'btn btn-default',
29173 html : '<i class="fa fa-trash"></i>'
29186 initEvents : function()
29188 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29189 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29191 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29192 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29194 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29195 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29197 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29198 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29200 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29201 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29203 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29204 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29206 this.bodyEl.on('click', this.onClick, this);
29207 this.downloadBtn.on('click', this.onDownload, this);
29208 this.trashBtn.on('click', this.onTrash, this);
29210 this.downloadBtn.hide();
29211 this.trashBtn.hide();
29213 if(this.showDownload){
29214 this.downloadBtn.show();
29217 if(this.showTrash){
29218 this.trashBtn.show();
29221 if(!this.showDownload && !this.showTrash) {
29222 this.footerEl.hide();
29227 initial : function()
29229 this.fireEvent('initial', this);
29233 onClick : function(e)
29235 e.preventDefault();
29237 this.fireEvent('click', this);
29240 onDownload : function(e)
29242 e.preventDefault();
29244 this.fireEvent('download', this);
29247 onTrash : function(e)
29249 e.preventDefault();
29251 this.fireEvent('trash', this);
29263 * @class Roo.bootstrap.NavProgressBar
29264 * @extends Roo.bootstrap.Component
29265 * Bootstrap NavProgressBar class
29268 * Create a new nav progress bar
29269 * @param {Object} config The config object
29272 Roo.bootstrap.NavProgressBar = function(config){
29273 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29275 this.bullets = this.bullets || [];
29277 // Roo.bootstrap.NavProgressBar.register(this);
29281 * Fires when the active item changes
29282 * @param {Roo.bootstrap.NavProgressBar} this
29283 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29284 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29291 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29296 getAutoCreate : function()
29298 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29302 cls : 'roo-navigation-bar-group',
29306 cls : 'roo-navigation-top-bar'
29310 cls : 'roo-navigation-bullets-bar',
29314 cls : 'roo-navigation-bar'
29321 cls : 'roo-navigation-bottom-bar'
29331 initEvents: function()
29336 onRender : function(ct, position)
29338 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29340 if(this.bullets.length){
29341 Roo.each(this.bullets, function(b){
29350 addItem : function(cfg)
29352 var item = new Roo.bootstrap.NavProgressItem(cfg);
29354 item.parentId = this.id;
29355 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29358 var top = new Roo.bootstrap.Element({
29360 cls : 'roo-navigation-bar-text'
29363 var bottom = new Roo.bootstrap.Element({
29365 cls : 'roo-navigation-bar-text'
29368 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29369 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29371 var topText = new Roo.bootstrap.Element({
29373 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29376 var bottomText = new Roo.bootstrap.Element({
29378 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29381 topText.onRender(top.el, null);
29382 bottomText.onRender(bottom.el, null);
29385 item.bottomEl = bottom;
29388 this.barItems.push(item);
29393 getActive : function()
29395 var active = false;
29397 Roo.each(this.barItems, function(v){
29399 if (!v.isActive()) {
29411 setActiveItem : function(item)
29415 Roo.each(this.barItems, function(v){
29416 if (v.rid == item.rid) {
29420 if (v.isActive()) {
29421 v.setActive(false);
29426 item.setActive(true);
29428 this.fireEvent('changed', this, item, prev);
29431 getBarItem: function(rid)
29435 Roo.each(this.barItems, function(e) {
29436 if (e.rid != rid) {
29447 indexOfItem : function(item)
29451 Roo.each(this.barItems, function(v, i){
29453 if (v.rid != item.rid) {
29464 setActiveNext : function()
29466 var i = this.indexOfItem(this.getActive());
29468 if (i > this.barItems.length) {
29472 this.setActiveItem(this.barItems[i+1]);
29475 setActivePrev : function()
29477 var i = this.indexOfItem(this.getActive());
29483 this.setActiveItem(this.barItems[i-1]);
29486 format : function()
29488 if(!this.barItems.length){
29492 var width = 100 / this.barItems.length;
29494 Roo.each(this.barItems, function(i){
29495 i.el.setStyle('width', width + '%');
29496 i.topEl.el.setStyle('width', width + '%');
29497 i.bottomEl.el.setStyle('width', width + '%');
29506 * Nav Progress Item
29511 * @class Roo.bootstrap.NavProgressItem
29512 * @extends Roo.bootstrap.Component
29513 * Bootstrap NavProgressItem class
29514 * @cfg {String} rid the reference id
29515 * @cfg {Boolean} active (true|false) Is item active default false
29516 * @cfg {Boolean} disabled (true|false) Is item active default false
29517 * @cfg {String} html
29518 * @cfg {String} position (top|bottom) text position default bottom
29519 * @cfg {String} icon show icon instead of number
29522 * Create a new NavProgressItem
29523 * @param {Object} config The config object
29525 Roo.bootstrap.NavProgressItem = function(config){
29526 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29531 * The raw click event for the entire grid.
29532 * @param {Roo.bootstrap.NavProgressItem} this
29533 * @param {Roo.EventObject} e
29540 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29546 position : 'bottom',
29549 getAutoCreate : function()
29551 var iconCls = 'roo-navigation-bar-item-icon';
29553 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29557 cls: 'roo-navigation-bar-item',
29567 cfg.cls += ' active';
29570 cfg.cls += ' disabled';
29576 disable : function()
29578 this.setDisabled(true);
29581 enable : function()
29583 this.setDisabled(false);
29586 initEvents: function()
29588 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29590 this.iconEl.on('click', this.onClick, this);
29593 onClick : function(e)
29595 e.preventDefault();
29601 if(this.fireEvent('click', this, e) === false){
29605 this.parent().setActiveItem(this);
29608 isActive: function ()
29610 return this.active;
29613 setActive : function(state)
29615 if(this.active == state){
29619 this.active = state;
29622 this.el.addClass('active');
29626 this.el.removeClass('active');
29631 setDisabled : function(state)
29633 if(this.disabled == state){
29637 this.disabled = state;
29640 this.el.addClass('disabled');
29644 this.el.removeClass('disabled');
29647 tooltipEl : function()
29649 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29662 * @class Roo.bootstrap.FieldLabel
29663 * @extends Roo.bootstrap.Component
29664 * Bootstrap FieldLabel class
29665 * @cfg {String} html contents of the element
29666 * @cfg {String} tag tag of the element default label
29667 * @cfg {String} cls class of the element
29668 * @cfg {String} target label target
29669 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29670 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29671 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29672 * @cfg {String} iconTooltip default "This field is required"
29675 * Create a new FieldLabel
29676 * @param {Object} config The config object
29679 Roo.bootstrap.FieldLabel = function(config){
29680 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29685 * Fires after the field has been marked as invalid.
29686 * @param {Roo.form.FieldLabel} this
29687 * @param {String} msg The validation message
29692 * Fires after the field has been validated with no errors.
29693 * @param {Roo.form.FieldLabel} this
29699 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29706 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29707 validClass : 'text-success fa fa-lg fa-check',
29708 iconTooltip : 'This field is required',
29710 getAutoCreate : function(){
29714 cls : 'roo-bootstrap-field-label ' + this.cls,
29720 tooltip : this.iconTooltip
29732 initEvents: function()
29734 Roo.bootstrap.Element.superclass.initEvents.call(this);
29736 this.iconEl = this.el.select('i', true).first();
29738 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29740 Roo.bootstrap.FieldLabel.register(this);
29744 * Mark this field as valid
29746 markValid : function()
29748 this.iconEl.show();
29750 this.iconEl.removeClass(this.invalidClass);
29752 this.iconEl.addClass(this.validClass);
29754 this.fireEvent('valid', this);
29758 * Mark this field as invalid
29759 * @param {String} msg The validation message
29761 markInvalid : function(msg)
29763 this.iconEl.show();
29765 this.iconEl.removeClass(this.validClass);
29767 this.iconEl.addClass(this.invalidClass);
29769 this.fireEvent('invalid', this, msg);
29775 Roo.apply(Roo.bootstrap.FieldLabel, {
29780 * register a FieldLabel Group
29781 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29783 register : function(label)
29785 if(this.groups.hasOwnProperty(label.target)){
29789 this.groups[label.target] = label;
29793 * fetch a FieldLabel Group based on the target
29794 * @param {string} target
29795 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29797 get: function(target) {
29798 if (typeof(this.groups[target]) == 'undefined') {
29802 return this.groups[target] ;
29811 * page DateSplitField.
29817 * @class Roo.bootstrap.DateSplitField
29818 * @extends Roo.bootstrap.Component
29819 * Bootstrap DateSplitField class
29820 * @cfg {string} fieldLabel - the label associated
29821 * @cfg {Number} labelWidth set the width of label (0-12)
29822 * @cfg {String} labelAlign (top|left)
29823 * @cfg {Boolean} dayAllowBlank (true|false) default false
29824 * @cfg {Boolean} monthAllowBlank (true|false) default false
29825 * @cfg {Boolean} yearAllowBlank (true|false) default false
29826 * @cfg {string} dayPlaceholder
29827 * @cfg {string} monthPlaceholder
29828 * @cfg {string} yearPlaceholder
29829 * @cfg {string} dayFormat default 'd'
29830 * @cfg {string} monthFormat default 'm'
29831 * @cfg {string} yearFormat default 'Y'
29832 * @cfg {Number} labellg set the width of label (1-12)
29833 * @cfg {Number} labelmd set the width of label (1-12)
29834 * @cfg {Number} labelsm set the width of label (1-12)
29835 * @cfg {Number} labelxs set the width of label (1-12)
29839 * Create a new DateSplitField
29840 * @param {Object} config The config object
29843 Roo.bootstrap.DateSplitField = function(config){
29844 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29850 * getting the data of years
29851 * @param {Roo.bootstrap.DateSplitField} this
29852 * @param {Object} years
29857 * getting the data of days
29858 * @param {Roo.bootstrap.DateSplitField} this
29859 * @param {Object} days
29864 * Fires after the field has been marked as invalid.
29865 * @param {Roo.form.Field} this
29866 * @param {String} msg The validation message
29871 * Fires after the field has been validated with no errors.
29872 * @param {Roo.form.Field} this
29878 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29881 labelAlign : 'top',
29883 dayAllowBlank : false,
29884 monthAllowBlank : false,
29885 yearAllowBlank : false,
29886 dayPlaceholder : '',
29887 monthPlaceholder : '',
29888 yearPlaceholder : '',
29892 isFormField : true,
29898 getAutoCreate : function()
29902 cls : 'row roo-date-split-field-group',
29907 cls : 'form-hidden-field roo-date-split-field-group-value',
29913 var labelCls = 'col-md-12';
29914 var contentCls = 'col-md-4';
29916 if(this.fieldLabel){
29920 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29924 html : this.fieldLabel
29929 if(this.labelAlign == 'left'){
29931 if(this.labelWidth > 12){
29932 label.style = "width: " + this.labelWidth + 'px';
29935 if(this.labelWidth < 13 && this.labelmd == 0){
29936 this.labelmd = this.labelWidth;
29939 if(this.labellg > 0){
29940 labelCls = ' col-lg-' + this.labellg;
29941 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29944 if(this.labelmd > 0){
29945 labelCls = ' col-md-' + this.labelmd;
29946 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29949 if(this.labelsm > 0){
29950 labelCls = ' col-sm-' + this.labelsm;
29951 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29954 if(this.labelxs > 0){
29955 labelCls = ' col-xs-' + this.labelxs;
29956 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29960 label.cls += ' ' + labelCls;
29962 cfg.cn.push(label);
29965 Roo.each(['day', 'month', 'year'], function(t){
29968 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29975 inputEl: function ()
29977 return this.el.select('.roo-date-split-field-group-value', true).first();
29980 onRender : function(ct, position)
29984 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29986 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29988 this.dayField = new Roo.bootstrap.ComboBox({
29989 allowBlank : this.dayAllowBlank,
29990 alwaysQuery : true,
29991 displayField : 'value',
29994 forceSelection : true,
29996 placeholder : this.dayPlaceholder,
29997 selectOnFocus : true,
29998 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29999 triggerAction : 'all',
30001 valueField : 'value',
30002 store : new Roo.data.SimpleStore({
30003 data : (function() {
30005 _this.fireEvent('days', _this, days);
30008 fields : [ 'value' ]
30011 select : function (_self, record, index)
30013 _this.setValue(_this.getValue());
30018 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30020 this.monthField = new Roo.bootstrap.MonthField({
30021 after : '<i class=\"fa fa-calendar\"></i>',
30022 allowBlank : this.monthAllowBlank,
30023 placeholder : this.monthPlaceholder,
30026 render : function (_self)
30028 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30029 e.preventDefault();
30033 select : function (_self, oldvalue, newvalue)
30035 _this.setValue(_this.getValue());
30040 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30042 this.yearField = new Roo.bootstrap.ComboBox({
30043 allowBlank : this.yearAllowBlank,
30044 alwaysQuery : true,
30045 displayField : 'value',
30048 forceSelection : true,
30050 placeholder : this.yearPlaceholder,
30051 selectOnFocus : true,
30052 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30053 triggerAction : 'all',
30055 valueField : 'value',
30056 store : new Roo.data.SimpleStore({
30057 data : (function() {
30059 _this.fireEvent('years', _this, years);
30062 fields : [ 'value' ]
30065 select : function (_self, record, index)
30067 _this.setValue(_this.getValue());
30072 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30075 setValue : function(v, format)
30077 this.inputEl.dom.value = v;
30079 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30081 var d = Date.parseDate(v, f);
30088 this.setDay(d.format(this.dayFormat));
30089 this.setMonth(d.format(this.monthFormat));
30090 this.setYear(d.format(this.yearFormat));
30097 setDay : function(v)
30099 this.dayField.setValue(v);
30100 this.inputEl.dom.value = this.getValue();
30105 setMonth : function(v)
30107 this.monthField.setValue(v, true);
30108 this.inputEl.dom.value = this.getValue();
30113 setYear : function(v)
30115 this.yearField.setValue(v);
30116 this.inputEl.dom.value = this.getValue();
30121 getDay : function()
30123 return this.dayField.getValue();
30126 getMonth : function()
30128 return this.monthField.getValue();
30131 getYear : function()
30133 return this.yearField.getValue();
30136 getValue : function()
30138 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30140 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30150 this.inputEl.dom.value = '';
30155 validate : function()
30157 var d = this.dayField.validate();
30158 var m = this.monthField.validate();
30159 var y = this.yearField.validate();
30164 (!this.dayAllowBlank && !d) ||
30165 (!this.monthAllowBlank && !m) ||
30166 (!this.yearAllowBlank && !y)
30171 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30180 this.markInvalid();
30185 markValid : function()
30188 var label = this.el.select('label', true).first();
30189 var icon = this.el.select('i.fa-star', true).first();
30195 this.fireEvent('valid', this);
30199 * Mark this field as invalid
30200 * @param {String} msg The validation message
30202 markInvalid : function(msg)
30205 var label = this.el.select('label', true).first();
30206 var icon = this.el.select('i.fa-star', true).first();
30208 if(label && !icon){
30209 this.el.select('.roo-date-split-field-label', true).createChild({
30211 cls : 'text-danger fa fa-lg fa-star',
30212 tooltip : 'This field is required',
30213 style : 'margin-right:5px;'
30217 this.fireEvent('invalid', this, msg);
30220 clearInvalid : function()
30222 var label = this.el.select('label', true).first();
30223 var icon = this.el.select('i.fa-star', true).first();
30229 this.fireEvent('valid', this);
30232 getName: function()
30242 * http://masonry.desandro.com
30244 * The idea is to render all the bricks based on vertical width...
30246 * The original code extends 'outlayer' - we might need to use that....
30252 * @class Roo.bootstrap.LayoutMasonry
30253 * @extends Roo.bootstrap.Component
30254 * Bootstrap Layout Masonry class
30257 * Create a new Element
30258 * @param {Object} config The config object
30261 Roo.bootstrap.LayoutMasonry = function(config){
30263 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30267 Roo.bootstrap.LayoutMasonry.register(this);
30273 * Fire after layout the items
30274 * @param {Roo.bootstrap.LayoutMasonry} this
30275 * @param {Roo.EventObject} e
30282 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30285 * @cfg {Boolean} isLayoutInstant = no animation?
30287 isLayoutInstant : false, // needed?
30290 * @cfg {Number} boxWidth width of the columns
30295 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30300 * @cfg {Number} padWidth padding below box..
30305 * @cfg {Number} gutter gutter width..
30310 * @cfg {Number} maxCols maximum number of columns
30316 * @cfg {Boolean} isAutoInitial defalut true
30318 isAutoInitial : true,
30323 * @cfg {Boolean} isHorizontal defalut false
30325 isHorizontal : false,
30327 currentSize : null,
30333 bricks: null, //CompositeElement
30337 _isLayoutInited : false,
30339 // isAlternative : false, // only use for vertical layout...
30342 * @cfg {Number} alternativePadWidth padding below box..
30344 alternativePadWidth : 50,
30346 selectedBrick : [],
30348 getAutoCreate : function(){
30350 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30354 cls: 'blog-masonary-wrapper ' + this.cls,
30356 cls : 'mas-boxes masonary'
30363 getChildContainer: function( )
30365 if (this.boxesEl) {
30366 return this.boxesEl;
30369 this.boxesEl = this.el.select('.mas-boxes').first();
30371 return this.boxesEl;
30375 initEvents : function()
30379 if(this.isAutoInitial){
30380 Roo.log('hook children rendered');
30381 this.on('childrenrendered', function() {
30382 Roo.log('children rendered');
30388 initial : function()
30390 this.selectedBrick = [];
30392 this.currentSize = this.el.getBox(true);
30394 Roo.EventManager.onWindowResize(this.resize, this);
30396 if(!this.isAutoInitial){
30404 //this.layout.defer(500,this);
30408 resize : function()
30410 var cs = this.el.getBox(true);
30413 this.currentSize.width == cs.width &&
30414 this.currentSize.x == cs.x &&
30415 this.currentSize.height == cs.height &&
30416 this.currentSize.y == cs.y
30418 Roo.log("no change in with or X or Y");
30422 this.currentSize = cs;
30428 layout : function()
30430 this._resetLayout();
30432 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30434 this.layoutItems( isInstant );
30436 this._isLayoutInited = true;
30438 this.fireEvent('layout', this);
30442 _resetLayout : function()
30444 if(this.isHorizontal){
30445 this.horizontalMeasureColumns();
30449 this.verticalMeasureColumns();
30453 verticalMeasureColumns : function()
30455 this.getContainerWidth();
30457 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30458 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30462 var boxWidth = this.boxWidth + this.padWidth;
30464 if(this.containerWidth < this.boxWidth){
30465 boxWidth = this.containerWidth
30468 var containerWidth = this.containerWidth;
30470 var cols = Math.floor(containerWidth / boxWidth);
30472 this.cols = Math.max( cols, 1 );
30474 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30476 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30478 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30480 this.colWidth = boxWidth + avail - this.padWidth;
30482 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30483 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30486 horizontalMeasureColumns : function()
30488 this.getContainerWidth();
30490 var boxWidth = this.boxWidth;
30492 if(this.containerWidth < boxWidth){
30493 boxWidth = this.containerWidth;
30496 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30498 this.el.setHeight(boxWidth);
30502 getContainerWidth : function()
30504 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30507 layoutItems : function( isInstant )
30509 Roo.log(this.bricks);
30511 var items = Roo.apply([], this.bricks);
30513 if(this.isHorizontal){
30514 this._horizontalLayoutItems( items , isInstant );
30518 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30519 // this._verticalAlternativeLayoutItems( items , isInstant );
30523 this._verticalLayoutItems( items , isInstant );
30527 _verticalLayoutItems : function ( items , isInstant)
30529 if ( !items || !items.length ) {
30534 ['xs', 'xs', 'xs', 'tall'],
30535 ['xs', 'xs', 'tall'],
30536 ['xs', 'xs', 'sm'],
30537 ['xs', 'xs', 'xs'],
30543 ['sm', 'xs', 'xs'],
30547 ['tall', 'xs', 'xs', 'xs'],
30548 ['tall', 'xs', 'xs'],
30560 Roo.each(items, function(item, k){
30562 switch (item.size) {
30563 // these layouts take up a full box,
30574 boxes.push([item]);
30597 var filterPattern = function(box, length)
30605 var pattern = box.slice(0, length);
30609 Roo.each(pattern, function(i){
30610 format.push(i.size);
30613 Roo.each(standard, function(s){
30615 if(String(s) != String(format)){
30624 if(!match && length == 1){
30629 filterPattern(box, length - 1);
30633 queue.push(pattern);
30635 box = box.slice(length, box.length);
30637 filterPattern(box, 4);
30643 Roo.each(boxes, function(box, k){
30649 if(box.length == 1){
30654 filterPattern(box, 4);
30658 this._processVerticalLayoutQueue( queue, isInstant );
30662 // _verticalAlternativeLayoutItems : function( items , isInstant )
30664 // if ( !items || !items.length ) {
30668 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30672 _horizontalLayoutItems : function ( items , isInstant)
30674 if ( !items || !items.length || items.length < 3) {
30680 var eItems = items.slice(0, 3);
30682 items = items.slice(3, items.length);
30685 ['xs', 'xs', 'xs', 'wide'],
30686 ['xs', 'xs', 'wide'],
30687 ['xs', 'xs', 'sm'],
30688 ['xs', 'xs', 'xs'],
30694 ['sm', 'xs', 'xs'],
30698 ['wide', 'xs', 'xs', 'xs'],
30699 ['wide', 'xs', 'xs'],
30712 Roo.each(items, function(item, k){
30714 switch (item.size) {
30725 boxes.push([item]);
30749 var filterPattern = function(box, length)
30757 var pattern = box.slice(0, length);
30761 Roo.each(pattern, function(i){
30762 format.push(i.size);
30765 Roo.each(standard, function(s){
30767 if(String(s) != String(format)){
30776 if(!match && length == 1){
30781 filterPattern(box, length - 1);
30785 queue.push(pattern);
30787 box = box.slice(length, box.length);
30789 filterPattern(box, 4);
30795 Roo.each(boxes, function(box, k){
30801 if(box.length == 1){
30806 filterPattern(box, 4);
30813 var pos = this.el.getBox(true);
30817 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30819 var hit_end = false;
30821 Roo.each(queue, function(box){
30825 Roo.each(box, function(b){
30827 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30837 Roo.each(box, function(b){
30839 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30842 mx = Math.max(mx, b.x);
30846 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30850 Roo.each(box, function(b){
30852 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30866 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30869 /** Sets position of item in DOM
30870 * @param {Element} item
30871 * @param {Number} x - horizontal position
30872 * @param {Number} y - vertical position
30873 * @param {Boolean} isInstant - disables transitions
30875 _processVerticalLayoutQueue : function( queue, isInstant )
30877 var pos = this.el.getBox(true);
30882 for (var i = 0; i < this.cols; i++){
30886 Roo.each(queue, function(box, k){
30888 var col = k % this.cols;
30890 Roo.each(box, function(b,kk){
30892 b.el.position('absolute');
30894 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30895 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30897 if(b.size == 'md-left' || b.size == 'md-right'){
30898 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30899 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30902 b.el.setWidth(width);
30903 b.el.setHeight(height);
30905 b.el.select('iframe',true).setSize(width,height);
30909 for (var i = 0; i < this.cols; i++){
30911 if(maxY[i] < maxY[col]){
30916 col = Math.min(col, i);
30920 x = pos.x + col * (this.colWidth + this.padWidth);
30924 var positions = [];
30926 switch (box.length){
30928 positions = this.getVerticalOneBoxColPositions(x, y, box);
30931 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30934 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30937 positions = this.getVerticalFourBoxColPositions(x, y, box);
30943 Roo.each(box, function(b,kk){
30945 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30947 var sz = b.el.getSize();
30949 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30957 for (var i = 0; i < this.cols; i++){
30958 mY = Math.max(mY, maxY[i]);
30961 this.el.setHeight(mY - pos.y);
30965 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30967 // var pos = this.el.getBox(true);
30970 // var maxX = pos.right;
30972 // var maxHeight = 0;
30974 // Roo.each(items, function(item, k){
30978 // item.el.position('absolute');
30980 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30982 // item.el.setWidth(width);
30984 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30986 // item.el.setHeight(height);
30989 // item.el.setXY([x, y], isInstant ? false : true);
30991 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30994 // y = y + height + this.alternativePadWidth;
30996 // maxHeight = maxHeight + height + this.alternativePadWidth;
31000 // this.el.setHeight(maxHeight);
31004 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31006 var pos = this.el.getBox(true);
31011 var maxX = pos.right;
31013 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31015 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31017 Roo.each(queue, function(box, k){
31019 Roo.each(box, function(b, kk){
31021 b.el.position('absolute');
31023 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31024 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31026 if(b.size == 'md-left' || b.size == 'md-right'){
31027 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31028 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31031 b.el.setWidth(width);
31032 b.el.setHeight(height);
31040 var positions = [];
31042 switch (box.length){
31044 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31047 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31050 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31053 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31059 Roo.each(box, function(b,kk){
31061 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31063 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31071 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31073 Roo.each(eItems, function(b,k){
31075 b.size = (k == 0) ? 'sm' : 'xs';
31076 b.x = (k == 0) ? 2 : 1;
31077 b.y = (k == 0) ? 2 : 1;
31079 b.el.position('absolute');
31081 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31083 b.el.setWidth(width);
31085 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31087 b.el.setHeight(height);
31091 var positions = [];
31094 x : maxX - this.unitWidth * 2 - this.gutter,
31099 x : maxX - this.unitWidth,
31100 y : minY + (this.unitWidth + this.gutter) * 2
31104 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31108 Roo.each(eItems, function(b,k){
31110 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31116 getVerticalOneBoxColPositions : function(x, y, box)
31120 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31122 if(box[0].size == 'md-left'){
31126 if(box[0].size == 'md-right'){
31131 x : x + (this.unitWidth + this.gutter) * rand,
31138 getVerticalTwoBoxColPositions : function(x, y, box)
31142 if(box[0].size == 'xs'){
31146 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31150 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31164 x : x + (this.unitWidth + this.gutter) * 2,
31165 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31172 getVerticalThreeBoxColPositions : function(x, y, box)
31176 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31184 x : x + (this.unitWidth + this.gutter) * 1,
31189 x : x + (this.unitWidth + this.gutter) * 2,
31197 if(box[0].size == 'xs' && box[1].size == 'xs'){
31206 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31210 x : x + (this.unitWidth + this.gutter) * 1,
31224 x : x + (this.unitWidth + this.gutter) * 2,
31229 x : x + (this.unitWidth + this.gutter) * 2,
31230 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31237 getVerticalFourBoxColPositions : function(x, y, box)
31241 if(box[0].size == 'xs'){
31250 y : y + (this.unitHeight + this.gutter) * 1
31255 y : y + (this.unitHeight + this.gutter) * 2
31259 x : x + (this.unitWidth + this.gutter) * 1,
31273 x : x + (this.unitWidth + this.gutter) * 2,
31278 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31279 y : y + (this.unitHeight + this.gutter) * 1
31283 x : x + (this.unitWidth + this.gutter) * 2,
31284 y : y + (this.unitWidth + this.gutter) * 2
31291 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31295 if(box[0].size == 'md-left'){
31297 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31304 if(box[0].size == 'md-right'){
31306 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31307 y : minY + (this.unitWidth + this.gutter) * 1
31313 var rand = Math.floor(Math.random() * (4 - box[0].y));
31316 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31317 y : minY + (this.unitWidth + this.gutter) * rand
31324 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31328 if(box[0].size == 'xs'){
31331 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31336 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31337 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31345 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31350 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31351 y : minY + (this.unitWidth + this.gutter) * 2
31358 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31362 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31365 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31370 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31371 y : minY + (this.unitWidth + this.gutter) * 1
31375 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31376 y : minY + (this.unitWidth + this.gutter) * 2
31383 if(box[0].size == 'xs' && box[1].size == 'xs'){
31386 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31391 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31396 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31397 y : minY + (this.unitWidth + this.gutter) * 1
31405 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31410 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31411 y : minY + (this.unitWidth + this.gutter) * 2
31415 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31416 y : minY + (this.unitWidth + this.gutter) * 2
31423 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31427 if(box[0].size == 'xs'){
31430 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31435 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31440 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),
31445 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31446 y : minY + (this.unitWidth + this.gutter) * 1
31454 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31459 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31460 y : minY + (this.unitWidth + this.gutter) * 2
31464 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31465 y : minY + (this.unitWidth + this.gutter) * 2
31469 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),
31470 y : minY + (this.unitWidth + this.gutter) * 2
31478 * remove a Masonry Brick
31479 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31481 removeBrick : function(brick_id)
31487 for (var i = 0; i<this.bricks.length; i++) {
31488 if (this.bricks[i].id == brick_id) {
31489 this.bricks.splice(i,1);
31490 this.el.dom.removeChild(Roo.get(brick_id).dom);
31497 * adds a Masonry Brick
31498 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31500 addBrick : function(cfg)
31502 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31503 //this.register(cn);
31504 cn.parentId = this.id;
31505 cn.onRender(this.el, null);
31510 * register a Masonry Brick
31511 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31514 register : function(brick)
31516 this.bricks.push(brick);
31517 brick.masonryId = this.id;
31521 * clear all the Masonry Brick
31523 clearAll : function()
31526 //this.getChildContainer().dom.innerHTML = "";
31527 this.el.dom.innerHTML = '';
31530 getSelected : function()
31532 if (!this.selectedBrick) {
31536 return this.selectedBrick;
31540 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31544 * register a Masonry Layout
31545 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31548 register : function(layout)
31550 this.groups[layout.id] = layout;
31553 * fetch a Masonry Layout based on the masonry layout ID
31554 * @param {string} the masonry layout to add
31555 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31558 get: function(layout_id) {
31559 if (typeof(this.groups[layout_id]) == 'undefined') {
31562 return this.groups[layout_id] ;
31574 * http://masonry.desandro.com
31576 * The idea is to render all the bricks based on vertical width...
31578 * The original code extends 'outlayer' - we might need to use that....
31584 * @class Roo.bootstrap.LayoutMasonryAuto
31585 * @extends Roo.bootstrap.Component
31586 * Bootstrap Layout Masonry class
31589 * Create a new Element
31590 * @param {Object} config The config object
31593 Roo.bootstrap.LayoutMasonryAuto = function(config){
31594 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31597 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31600 * @cfg {Boolean} isFitWidth - resize the width..
31602 isFitWidth : false, // options..
31604 * @cfg {Boolean} isOriginLeft = left align?
31606 isOriginLeft : true,
31608 * @cfg {Boolean} isOriginTop = top align?
31610 isOriginTop : false,
31612 * @cfg {Boolean} isLayoutInstant = no animation?
31614 isLayoutInstant : false, // needed?
31616 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31618 isResizingContainer : true,
31620 * @cfg {Number} columnWidth width of the columns
31626 * @cfg {Number} maxCols maximum number of columns
31631 * @cfg {Number} padHeight padding below box..
31637 * @cfg {Boolean} isAutoInitial defalut true
31640 isAutoInitial : true,
31646 initialColumnWidth : 0,
31647 currentSize : null,
31649 colYs : null, // array.
31656 bricks: null, //CompositeElement
31657 cols : 0, // array?
31658 // element : null, // wrapped now this.el
31659 _isLayoutInited : null,
31662 getAutoCreate : function(){
31666 cls: 'blog-masonary-wrapper ' + this.cls,
31668 cls : 'mas-boxes masonary'
31675 getChildContainer: function( )
31677 if (this.boxesEl) {
31678 return this.boxesEl;
31681 this.boxesEl = this.el.select('.mas-boxes').first();
31683 return this.boxesEl;
31687 initEvents : function()
31691 if(this.isAutoInitial){
31692 Roo.log('hook children rendered');
31693 this.on('childrenrendered', function() {
31694 Roo.log('children rendered');
31701 initial : function()
31703 this.reloadItems();
31705 this.currentSize = this.el.getBox(true);
31707 /// was window resize... - let's see if this works..
31708 Roo.EventManager.onWindowResize(this.resize, this);
31710 if(!this.isAutoInitial){
31715 this.layout.defer(500,this);
31718 reloadItems: function()
31720 this.bricks = this.el.select('.masonry-brick', true);
31722 this.bricks.each(function(b) {
31723 //Roo.log(b.getSize());
31724 if (!b.attr('originalwidth')) {
31725 b.attr('originalwidth', b.getSize().width);
31730 Roo.log(this.bricks.elements.length);
31733 resize : function()
31736 var cs = this.el.getBox(true);
31738 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31739 Roo.log("no change in with or X");
31742 this.currentSize = cs;
31746 layout : function()
31749 this._resetLayout();
31750 //this._manageStamps();
31752 // don't animate first layout
31753 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31754 this.layoutItems( isInstant );
31756 // flag for initalized
31757 this._isLayoutInited = true;
31760 layoutItems : function( isInstant )
31762 //var items = this._getItemsForLayout( this.items );
31763 // original code supports filtering layout items.. we just ignore it..
31765 this._layoutItems( this.bricks , isInstant );
31767 this._postLayout();
31769 _layoutItems : function ( items , isInstant)
31771 //this.fireEvent( 'layout', this, items );
31774 if ( !items || !items.elements.length ) {
31775 // no items, emit event with empty array
31780 items.each(function(item) {
31781 Roo.log("layout item");
31783 // get x/y object from method
31784 var position = this._getItemLayoutPosition( item );
31786 position.item = item;
31787 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31788 queue.push( position );
31791 this._processLayoutQueue( queue );
31793 /** Sets position of item in DOM
31794 * @param {Element} item
31795 * @param {Number} x - horizontal position
31796 * @param {Number} y - vertical position
31797 * @param {Boolean} isInstant - disables transitions
31799 _processLayoutQueue : function( queue )
31801 for ( var i=0, len = queue.length; i < len; i++ ) {
31802 var obj = queue[i];
31803 obj.item.position('absolute');
31804 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31810 * Any logic you want to do after each layout,
31811 * i.e. size the container
31813 _postLayout : function()
31815 this.resizeContainer();
31818 resizeContainer : function()
31820 if ( !this.isResizingContainer ) {
31823 var size = this._getContainerSize();
31825 this.el.setSize(size.width,size.height);
31826 this.boxesEl.setSize(size.width,size.height);
31832 _resetLayout : function()
31834 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31835 this.colWidth = this.el.getWidth();
31836 //this.gutter = this.el.getWidth();
31838 this.measureColumns();
31844 this.colYs.push( 0 );
31850 measureColumns : function()
31852 this.getContainerWidth();
31853 // if columnWidth is 0, default to outerWidth of first item
31854 if ( !this.columnWidth ) {
31855 var firstItem = this.bricks.first();
31856 Roo.log(firstItem);
31857 this.columnWidth = this.containerWidth;
31858 if (firstItem && firstItem.attr('originalwidth') ) {
31859 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31861 // columnWidth fall back to item of first element
31862 Roo.log("set column width?");
31863 this.initialColumnWidth = this.columnWidth ;
31865 // if first elem has no width, default to size of container
31870 if (this.initialColumnWidth) {
31871 this.columnWidth = this.initialColumnWidth;
31876 // column width is fixed at the top - however if container width get's smaller we should
31879 // this bit calcs how man columns..
31881 var columnWidth = this.columnWidth += this.gutter;
31883 // calculate columns
31884 var containerWidth = this.containerWidth + this.gutter;
31886 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31887 // fix rounding errors, typically with gutters
31888 var excess = columnWidth - containerWidth % columnWidth;
31891 // if overshoot is less than a pixel, round up, otherwise floor it
31892 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31893 cols = Math[ mathMethod ]( cols );
31894 this.cols = Math.max( cols, 1 );
31895 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31897 // padding positioning..
31898 var totalColWidth = this.cols * this.columnWidth;
31899 var padavail = this.containerWidth - totalColWidth;
31900 // so for 2 columns - we need 3 'pads'
31902 var padNeeded = (1+this.cols) * this.padWidth;
31904 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31906 this.columnWidth += padExtra
31907 //this.padWidth = Math.floor(padavail / ( this.cols));
31909 // adjust colum width so that padding is fixed??
31911 // we have 3 columns ... total = width * 3
31912 // we have X left over... that should be used by
31914 //if (this.expandC) {
31922 getContainerWidth : function()
31924 /* // container is parent if fit width
31925 var container = this.isFitWidth ? this.element.parentNode : this.element;
31926 // check that this.size and size are there
31927 // IE8 triggers resize on body size change, so they might not be
31929 var size = getSize( container ); //FIXME
31930 this.containerWidth = size && size.innerWidth; //FIXME
31933 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31937 _getItemLayoutPosition : function( item ) // what is item?
31939 // we resize the item to our columnWidth..
31941 item.setWidth(this.columnWidth);
31942 item.autoBoxAdjust = false;
31944 var sz = item.getSize();
31946 // how many columns does this brick span
31947 var remainder = this.containerWidth % this.columnWidth;
31949 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31950 // round if off by 1 pixel, otherwise use ceil
31951 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31952 colSpan = Math.min( colSpan, this.cols );
31954 // normally this should be '1' as we dont' currently allow multi width columns..
31956 var colGroup = this._getColGroup( colSpan );
31957 // get the minimum Y value from the columns
31958 var minimumY = Math.min.apply( Math, colGroup );
31959 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31961 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31963 // position the brick
31965 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31966 y: this.currentSize.y + minimumY + this.padHeight
31970 // apply setHeight to necessary columns
31971 var setHeight = minimumY + sz.height + this.padHeight;
31972 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31974 var setSpan = this.cols + 1 - colGroup.length;
31975 for ( var i = 0; i < setSpan; i++ ) {
31976 this.colYs[ shortColIndex + i ] = setHeight ;
31983 * @param {Number} colSpan - number of columns the element spans
31984 * @returns {Array} colGroup
31986 _getColGroup : function( colSpan )
31988 if ( colSpan < 2 ) {
31989 // if brick spans only one column, use all the column Ys
31994 // how many different places could this brick fit horizontally
31995 var groupCount = this.cols + 1 - colSpan;
31996 // for each group potential horizontal position
31997 for ( var i = 0; i < groupCount; i++ ) {
31998 // make an array of colY values for that one group
31999 var groupColYs = this.colYs.slice( i, i + colSpan );
32000 // and get the max value of the array
32001 colGroup[i] = Math.max.apply( Math, groupColYs );
32006 _manageStamp : function( stamp )
32008 var stampSize = stamp.getSize();
32009 var offset = stamp.getBox();
32010 // get the columns that this stamp affects
32011 var firstX = this.isOriginLeft ? offset.x : offset.right;
32012 var lastX = firstX + stampSize.width;
32013 var firstCol = Math.floor( firstX / this.columnWidth );
32014 firstCol = Math.max( 0, firstCol );
32016 var lastCol = Math.floor( lastX / this.columnWidth );
32017 // lastCol should not go over if multiple of columnWidth #425
32018 lastCol -= lastX % this.columnWidth ? 0 : 1;
32019 lastCol = Math.min( this.cols - 1, lastCol );
32021 // set colYs to bottom of the stamp
32022 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32025 for ( var i = firstCol; i <= lastCol; i++ ) {
32026 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32031 _getContainerSize : function()
32033 this.maxY = Math.max.apply( Math, this.colYs );
32038 if ( this.isFitWidth ) {
32039 size.width = this._getContainerFitWidth();
32045 _getContainerFitWidth : function()
32047 var unusedCols = 0;
32048 // count unused columns
32051 if ( this.colYs[i] !== 0 ) {
32056 // fit container to columns that have been used
32057 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32060 needsResizeLayout : function()
32062 var previousWidth = this.containerWidth;
32063 this.getContainerWidth();
32064 return previousWidth !== this.containerWidth;
32079 * @class Roo.bootstrap.MasonryBrick
32080 * @extends Roo.bootstrap.Component
32081 * Bootstrap MasonryBrick class
32084 * Create a new MasonryBrick
32085 * @param {Object} config The config object
32088 Roo.bootstrap.MasonryBrick = function(config){
32090 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32092 Roo.bootstrap.MasonryBrick.register(this);
32098 * When a MasonryBrick is clcik
32099 * @param {Roo.bootstrap.MasonryBrick} this
32100 * @param {Roo.EventObject} e
32106 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32109 * @cfg {String} title
32113 * @cfg {String} html
32117 * @cfg {String} bgimage
32121 * @cfg {String} videourl
32125 * @cfg {String} cls
32129 * @cfg {String} href
32133 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32138 * @cfg {String} placetitle (center|bottom)
32143 * @cfg {Boolean} isFitContainer defalut true
32145 isFitContainer : true,
32148 * @cfg {Boolean} preventDefault defalut false
32150 preventDefault : false,
32153 * @cfg {Boolean} inverse defalut false
32155 maskInverse : false,
32157 getAutoCreate : function()
32159 if(!this.isFitContainer){
32160 return this.getSplitAutoCreate();
32163 var cls = 'masonry-brick masonry-brick-full';
32165 if(this.href.length){
32166 cls += ' masonry-brick-link';
32169 if(this.bgimage.length){
32170 cls += ' masonry-brick-image';
32173 if(this.maskInverse){
32174 cls += ' mask-inverse';
32177 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32178 cls += ' enable-mask';
32182 cls += ' masonry-' + this.size + '-brick';
32185 if(this.placetitle.length){
32187 switch (this.placetitle) {
32189 cls += ' masonry-center-title';
32192 cls += ' masonry-bottom-title';
32199 if(!this.html.length && !this.bgimage.length){
32200 cls += ' masonry-center-title';
32203 if(!this.html.length && this.bgimage.length){
32204 cls += ' masonry-bottom-title';
32209 cls += ' ' + this.cls;
32213 tag: (this.href.length) ? 'a' : 'div',
32218 cls: 'masonry-brick-mask'
32222 cls: 'masonry-brick-paragraph',
32228 if(this.href.length){
32229 cfg.href = this.href;
32232 var cn = cfg.cn[1].cn;
32234 if(this.title.length){
32237 cls: 'masonry-brick-title',
32242 if(this.html.length){
32245 cls: 'masonry-brick-text',
32250 if (!this.title.length && !this.html.length) {
32251 cfg.cn[1].cls += ' hide';
32254 if(this.bgimage.length){
32257 cls: 'masonry-brick-image-view',
32262 if(this.videourl.length){
32263 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32264 // youtube support only?
32267 cls: 'masonry-brick-image-view',
32270 allowfullscreen : true
32278 getSplitAutoCreate : function()
32280 var cls = 'masonry-brick masonry-brick-split';
32282 if(this.href.length){
32283 cls += ' masonry-brick-link';
32286 if(this.bgimage.length){
32287 cls += ' masonry-brick-image';
32291 cls += ' masonry-' + this.size + '-brick';
32294 switch (this.placetitle) {
32296 cls += ' masonry-center-title';
32299 cls += ' masonry-bottom-title';
32302 if(!this.bgimage.length){
32303 cls += ' masonry-center-title';
32306 if(this.bgimage.length){
32307 cls += ' masonry-bottom-title';
32313 cls += ' ' + this.cls;
32317 tag: (this.href.length) ? 'a' : 'div',
32322 cls: 'masonry-brick-split-head',
32326 cls: 'masonry-brick-paragraph',
32333 cls: 'masonry-brick-split-body',
32339 if(this.href.length){
32340 cfg.href = this.href;
32343 if(this.title.length){
32344 cfg.cn[0].cn[0].cn.push({
32346 cls: 'masonry-brick-title',
32351 if(this.html.length){
32352 cfg.cn[1].cn.push({
32354 cls: 'masonry-brick-text',
32359 if(this.bgimage.length){
32360 cfg.cn[0].cn.push({
32362 cls: 'masonry-brick-image-view',
32367 if(this.videourl.length){
32368 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32369 // youtube support only?
32370 cfg.cn[0].cn.cn.push({
32372 cls: 'masonry-brick-image-view',
32375 allowfullscreen : true
32382 initEvents: function()
32384 switch (this.size) {
32417 this.el.on('touchstart', this.onTouchStart, this);
32418 this.el.on('touchmove', this.onTouchMove, this);
32419 this.el.on('touchend', this.onTouchEnd, this);
32420 this.el.on('contextmenu', this.onContextMenu, this);
32422 this.el.on('mouseenter' ,this.enter, this);
32423 this.el.on('mouseleave', this.leave, this);
32424 this.el.on('click', this.onClick, this);
32427 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32428 this.parent().bricks.push(this);
32433 onClick: function(e, el)
32435 var time = this.endTimer - this.startTimer;
32436 // Roo.log(e.preventDefault());
32439 e.preventDefault();
32444 if(!this.preventDefault){
32448 e.preventDefault();
32450 if (this.activcClass != '') {
32451 this.selectBrick();
32454 this.fireEvent('click', this);
32457 enter: function(e, el)
32459 e.preventDefault();
32461 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32465 if(this.bgimage.length && this.html.length){
32466 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32470 leave: function(e, el)
32472 e.preventDefault();
32474 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32478 if(this.bgimage.length && this.html.length){
32479 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32483 onTouchStart: function(e, el)
32485 // e.preventDefault();
32487 this.touchmoved = false;
32489 if(!this.isFitContainer){
32493 if(!this.bgimage.length || !this.html.length){
32497 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32499 this.timer = new Date().getTime();
32503 onTouchMove: function(e, el)
32505 this.touchmoved = true;
32508 onContextMenu : function(e,el)
32510 e.preventDefault();
32511 e.stopPropagation();
32515 onTouchEnd: function(e, el)
32517 // e.preventDefault();
32519 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32526 if(!this.bgimage.length || !this.html.length){
32528 if(this.href.length){
32529 window.location.href = this.href;
32535 if(!this.isFitContainer){
32539 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32541 window.location.href = this.href;
32544 //selection on single brick only
32545 selectBrick : function() {
32547 if (!this.parentId) {
32551 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32552 var index = m.selectedBrick.indexOf(this.id);
32555 m.selectedBrick.splice(index,1);
32556 this.el.removeClass(this.activeClass);
32560 for(var i = 0; i < m.selectedBrick.length; i++) {
32561 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32562 b.el.removeClass(b.activeClass);
32565 m.selectedBrick = [];
32567 m.selectedBrick.push(this.id);
32568 this.el.addClass(this.activeClass);
32574 Roo.apply(Roo.bootstrap.MasonryBrick, {
32577 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32579 * register a Masonry Brick
32580 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32583 register : function(brick)
32585 //this.groups[brick.id] = brick;
32586 this.groups.add(brick.id, brick);
32589 * fetch a masonry brick based on the masonry brick ID
32590 * @param {string} the masonry brick to add
32591 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32594 get: function(brick_id)
32596 // if (typeof(this.groups[brick_id]) == 'undefined') {
32599 // return this.groups[brick_id] ;
32601 if(this.groups.key(brick_id)) {
32602 return this.groups.key(brick_id);
32620 * @class Roo.bootstrap.Brick
32621 * @extends Roo.bootstrap.Component
32622 * Bootstrap Brick class
32625 * Create a new Brick
32626 * @param {Object} config The config object
32629 Roo.bootstrap.Brick = function(config){
32630 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32636 * When a Brick is click
32637 * @param {Roo.bootstrap.Brick} this
32638 * @param {Roo.EventObject} e
32644 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32647 * @cfg {String} title
32651 * @cfg {String} html
32655 * @cfg {String} bgimage
32659 * @cfg {String} cls
32663 * @cfg {String} href
32667 * @cfg {String} video
32671 * @cfg {Boolean} square
32675 getAutoCreate : function()
32677 var cls = 'roo-brick';
32679 if(this.href.length){
32680 cls += ' roo-brick-link';
32683 if(this.bgimage.length){
32684 cls += ' roo-brick-image';
32687 if(!this.html.length && !this.bgimage.length){
32688 cls += ' roo-brick-center-title';
32691 if(!this.html.length && this.bgimage.length){
32692 cls += ' roo-brick-bottom-title';
32696 cls += ' ' + this.cls;
32700 tag: (this.href.length) ? 'a' : 'div',
32705 cls: 'roo-brick-paragraph',
32711 if(this.href.length){
32712 cfg.href = this.href;
32715 var cn = cfg.cn[0].cn;
32717 if(this.title.length){
32720 cls: 'roo-brick-title',
32725 if(this.html.length){
32728 cls: 'roo-brick-text',
32735 if(this.bgimage.length){
32738 cls: 'roo-brick-image-view',
32746 initEvents: function()
32748 if(this.title.length || this.html.length){
32749 this.el.on('mouseenter' ,this.enter, this);
32750 this.el.on('mouseleave', this.leave, this);
32753 Roo.EventManager.onWindowResize(this.resize, this);
32755 if(this.bgimage.length){
32756 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32757 this.imageEl.on('load', this.onImageLoad, this);
32764 onImageLoad : function()
32769 resize : function()
32771 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32773 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32775 if(this.bgimage.length){
32776 var image = this.el.select('.roo-brick-image-view', true).first();
32778 image.setWidth(paragraph.getWidth());
32781 image.setHeight(paragraph.getWidth());
32784 this.el.setHeight(image.getHeight());
32785 paragraph.setHeight(image.getHeight());
32791 enter: function(e, el)
32793 e.preventDefault();
32795 if(this.bgimage.length){
32796 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32797 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32801 leave: function(e, el)
32803 e.preventDefault();
32805 if(this.bgimage.length){
32806 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32807 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32823 * @class Roo.bootstrap.NumberField
32824 * @extends Roo.bootstrap.Input
32825 * Bootstrap NumberField class
32831 * Create a new NumberField
32832 * @param {Object} config The config object
32835 Roo.bootstrap.NumberField = function(config){
32836 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32839 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32842 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32844 allowDecimals : true,
32846 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32848 decimalSeparator : ".",
32850 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32852 decimalPrecision : 2,
32854 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32856 allowNegative : true,
32858 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32860 minValue : Number.NEGATIVE_INFINITY,
32862 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32864 maxValue : Number.MAX_VALUE,
32866 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32868 minText : "The minimum value for this field is {0}",
32870 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32872 maxText : "The maximum value for this field is {0}",
32874 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32875 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32877 nanText : "{0} is not a valid number",
32879 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32884 initEvents : function()
32886 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32888 var allowed = "0123456789";
32890 if(this.allowDecimals){
32891 allowed += this.decimalSeparator;
32894 if(this.allowNegative){
32898 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32900 var keyPress = function(e){
32902 var k = e.getKey();
32904 var c = e.getCharCode();
32907 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32908 allowed.indexOf(String.fromCharCode(c)) === -1
32914 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32918 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32923 this.el.on("keypress", keyPress, this);
32926 validateValue : function(value)
32929 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32933 var num = this.parseValue(value);
32936 this.markInvalid(String.format(this.nanText, value));
32940 if(num < this.minValue){
32941 this.markInvalid(String.format(this.minText, this.minValue));
32945 if(num > this.maxValue){
32946 this.markInvalid(String.format(this.maxText, this.maxValue));
32953 getValue : function()
32955 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32958 parseValue : function(value)
32960 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32961 return isNaN(value) ? '' : value;
32964 fixPrecision : function(value)
32966 var nan = isNaN(value);
32968 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32969 return nan ? '' : value;
32971 return parseFloat(value).toFixed(this.decimalPrecision);
32974 setValue : function(v)
32976 v = this.fixPrecision(v);
32977 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32980 decimalPrecisionFcn : function(v)
32982 return Math.floor(v);
32985 beforeBlur : function()
32991 var v = this.parseValue(this.getRawValue());
33006 * @class Roo.bootstrap.DocumentSlider
33007 * @extends Roo.bootstrap.Component
33008 * Bootstrap DocumentSlider class
33011 * Create a new DocumentViewer
33012 * @param {Object} config The config object
33015 Roo.bootstrap.DocumentSlider = function(config){
33016 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33023 * Fire after initEvent
33024 * @param {Roo.bootstrap.DocumentSlider} this
33029 * Fire after update
33030 * @param {Roo.bootstrap.DocumentSlider} this
33036 * @param {Roo.bootstrap.DocumentSlider} this
33042 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33048 getAutoCreate : function()
33052 cls : 'roo-document-slider',
33056 cls : 'roo-document-slider-header',
33060 cls : 'roo-document-slider-header-title'
33066 cls : 'roo-document-slider-body',
33070 cls : 'roo-document-slider-prev',
33074 cls : 'fa fa-chevron-left'
33080 cls : 'roo-document-slider-thumb',
33084 cls : 'roo-document-slider-image'
33090 cls : 'roo-document-slider-next',
33094 cls : 'fa fa-chevron-right'
33106 initEvents : function()
33108 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33109 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33111 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33112 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33114 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33115 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33117 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33118 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33120 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33121 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33123 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33124 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33126 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33127 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33129 this.thumbEl.on('click', this.onClick, this);
33131 this.prevIndicator.on('click', this.prev, this);
33133 this.nextIndicator.on('click', this.next, this);
33137 initial : function()
33139 if(this.files.length){
33140 this.indicator = 1;
33144 this.fireEvent('initial', this);
33147 update : function()
33149 this.imageEl.attr('src', this.files[this.indicator - 1]);
33151 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33153 this.prevIndicator.show();
33155 if(this.indicator == 1){
33156 this.prevIndicator.hide();
33159 this.nextIndicator.show();
33161 if(this.indicator == this.files.length){
33162 this.nextIndicator.hide();
33165 this.thumbEl.scrollTo('top');
33167 this.fireEvent('update', this);
33170 onClick : function(e)
33172 e.preventDefault();
33174 this.fireEvent('click', this);
33179 e.preventDefault();
33181 this.indicator = Math.max(1, this.indicator - 1);
33188 e.preventDefault();
33190 this.indicator = Math.min(this.files.length, this.indicator + 1);
33204 * @class Roo.bootstrap.RadioSet
33205 * @extends Roo.bootstrap.Input
33206 * Bootstrap RadioSet class
33207 * @cfg {String} indicatorpos (left|right) default left
33208 * @cfg {Boolean} inline (true|false) inline the element (default true)
33209 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33211 * Create a new RadioSet
33212 * @param {Object} config The config object
33215 Roo.bootstrap.RadioSet = function(config){
33217 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33221 Roo.bootstrap.RadioSet.register(this);
33226 * Fires when the element is checked or unchecked.
33227 * @param {Roo.bootstrap.RadioSet} this This radio
33228 * @param {Roo.bootstrap.Radio} item The checked item
33235 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33243 indicatorpos : 'left',
33245 getAutoCreate : function()
33249 cls : 'roo-radio-set-label',
33253 html : this.fieldLabel
33258 if(this.indicatorpos == 'left'){
33261 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33262 tooltip : 'This field is required'
33267 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33268 tooltip : 'This field is required'
33274 cls : 'roo-radio-set-items'
33277 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33279 if (align === 'left' && this.fieldLabel.length) {
33282 cls : "roo-radio-set-right",
33288 if(this.labelWidth > 12){
33289 label.style = "width: " + this.labelWidth + 'px';
33292 if(this.labelWidth < 13 && this.labelmd == 0){
33293 this.labelmd = this.labelWidth;
33296 if(this.labellg > 0){
33297 label.cls += ' col-lg-' + this.labellg;
33298 items.cls += ' col-lg-' + (12 - this.labellg);
33301 if(this.labelmd > 0){
33302 label.cls += ' col-md-' + this.labelmd;
33303 items.cls += ' col-md-' + (12 - this.labelmd);
33306 if(this.labelsm > 0){
33307 label.cls += ' col-sm-' + this.labelsm;
33308 items.cls += ' col-sm-' + (12 - this.labelsm);
33311 if(this.labelxs > 0){
33312 label.cls += ' col-xs-' + this.labelxs;
33313 items.cls += ' col-xs-' + (12 - this.labelxs);
33319 cls : 'roo-radio-set',
33323 cls : 'roo-radio-set-input',
33326 value : this.value ? this.value : ''
33333 if(this.weight.length){
33334 cfg.cls += ' roo-radio-' + this.weight;
33338 cfg.cls += ' roo-radio-set-inline';
33342 ['xs','sm','md','lg'].map(function(size){
33343 if (settings[size]) {
33344 cfg.cls += ' col-' + size + '-' + settings[size];
33352 initEvents : function()
33354 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33355 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33357 if(!this.fieldLabel.length){
33358 this.labelEl.hide();
33361 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33362 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33364 this.indicatorEl().addClass('invisible');
33366 this.originalValue = this.getValue();
33370 inputEl: function ()
33372 return this.el.select('.roo-radio-set-input', true).first();
33375 getChildContainer : function()
33377 return this.itemsEl;
33380 register : function(item)
33382 this.radioes.push(item);
33386 validate : function()
33390 Roo.each(this.radioes, function(i){
33399 if(this.allowBlank) {
33403 if(this.disabled || valid){
33408 this.markInvalid();
33413 markValid : function()
33415 if(this.labelEl.isVisible(true)){
33416 this.indicatorEl().removeClass('visible');
33417 this.indicatorEl().addClass('invisible');
33420 this.el.removeClass([this.invalidClass, this.validClass]);
33421 this.el.addClass(this.validClass);
33423 this.fireEvent('valid', this);
33426 markInvalid : function(msg)
33428 if(this.allowBlank || this.disabled){
33432 if(this.labelEl.isVisible(true)){
33433 this.indicatorEl().removeClass('invisible');
33434 this.indicatorEl().addClass('visible');
33437 this.el.removeClass([this.invalidClass, this.validClass]);
33438 this.el.addClass(this.invalidClass);
33440 this.fireEvent('invalid', this, msg);
33444 setValue : function(v, suppressEvent)
33448 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33451 Roo.each(this.radioes, function(i){
33454 i.el.removeClass('checked');
33456 if(i.value === v || i.value.toString() === v.toString()){
33458 i.el.addClass('checked');
33460 if(suppressEvent !== true){
33461 this.fireEvent('check', this, i);
33470 clearInvalid : function(){
33472 if(!this.el || this.preventMark){
33476 this.el.removeClass([this.invalidClass]);
33478 this.fireEvent('valid', this);
33483 Roo.apply(Roo.bootstrap.RadioSet, {
33487 register : function(set)
33489 this.groups[set.name] = set;
33492 get: function(name)
33494 if (typeof(this.groups[name]) == 'undefined') {
33498 return this.groups[name] ;
33504 * Ext JS Library 1.1.1
33505 * Copyright(c) 2006-2007, Ext JS, LLC.
33507 * Originally Released Under LGPL - original licence link has changed is not relivant.
33510 * <script type="text/javascript">
33515 * @class Roo.bootstrap.SplitBar
33516 * @extends Roo.util.Observable
33517 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33521 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33522 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33523 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33524 split.minSize = 100;
33525 split.maxSize = 600;
33526 split.animate = true;
33527 split.on('moved', splitterMoved);
33530 * Create a new SplitBar
33531 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33532 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33533 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33534 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33535 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33536 position of the SplitBar).
33538 Roo.bootstrap.SplitBar = function(cfg){
33543 // dragElement : elm
33544 // resizingElement: el,
33546 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33547 // placement : Roo.bootstrap.SplitBar.LEFT ,
33548 // existingProxy ???
33551 this.el = Roo.get(cfg.dragElement, true);
33552 this.el.dom.unselectable = "on";
33554 this.resizingEl = Roo.get(cfg.resizingElement, true);
33558 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33559 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33562 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33565 * The minimum size of the resizing element. (Defaults to 0)
33571 * The maximum size of the resizing element. (Defaults to 2000)
33574 this.maxSize = 2000;
33577 * Whether to animate the transition to the new size
33580 this.animate = false;
33583 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33586 this.useShim = false;
33591 if(!cfg.existingProxy){
33593 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33595 this.proxy = Roo.get(cfg.existingProxy).dom;
33598 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33601 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33604 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33607 this.dragSpecs = {};
33610 * @private The adapter to use to positon and resize elements
33612 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33613 this.adapter.init(this);
33615 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33617 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33618 this.el.addClass("roo-splitbar-h");
33621 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33622 this.el.addClass("roo-splitbar-v");
33628 * Fires when the splitter is moved (alias for {@link #event-moved})
33629 * @param {Roo.bootstrap.SplitBar} this
33630 * @param {Number} newSize the new width or height
33635 * Fires when the splitter is moved
33636 * @param {Roo.bootstrap.SplitBar} this
33637 * @param {Number} newSize the new width or height
33641 * @event beforeresize
33642 * Fires before the splitter is dragged
33643 * @param {Roo.bootstrap.SplitBar} this
33645 "beforeresize" : true,
33647 "beforeapply" : true
33650 Roo.util.Observable.call(this);
33653 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33654 onStartProxyDrag : function(x, y){
33655 this.fireEvent("beforeresize", this);
33657 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33659 o.enableDisplayMode("block");
33660 // all splitbars share the same overlay
33661 Roo.bootstrap.SplitBar.prototype.overlay = o;
33663 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33664 this.overlay.show();
33665 Roo.get(this.proxy).setDisplayed("block");
33666 var size = this.adapter.getElementSize(this);
33667 this.activeMinSize = this.getMinimumSize();;
33668 this.activeMaxSize = this.getMaximumSize();;
33669 var c1 = size - this.activeMinSize;
33670 var c2 = Math.max(this.activeMaxSize - size, 0);
33671 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33672 this.dd.resetConstraints();
33673 this.dd.setXConstraint(
33674 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33675 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33677 this.dd.setYConstraint(0, 0);
33679 this.dd.resetConstraints();
33680 this.dd.setXConstraint(0, 0);
33681 this.dd.setYConstraint(
33682 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33683 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33686 this.dragSpecs.startSize = size;
33687 this.dragSpecs.startPoint = [x, y];
33688 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33692 * @private Called after the drag operation by the DDProxy
33694 onEndProxyDrag : function(e){
33695 Roo.get(this.proxy).setDisplayed(false);
33696 var endPoint = Roo.lib.Event.getXY(e);
33698 this.overlay.hide();
33701 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33702 newSize = this.dragSpecs.startSize +
33703 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33704 endPoint[0] - this.dragSpecs.startPoint[0] :
33705 this.dragSpecs.startPoint[0] - endPoint[0]
33708 newSize = this.dragSpecs.startSize +
33709 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33710 endPoint[1] - this.dragSpecs.startPoint[1] :
33711 this.dragSpecs.startPoint[1] - endPoint[1]
33714 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33715 if(newSize != this.dragSpecs.startSize){
33716 if(this.fireEvent('beforeapply', this, newSize) !== false){
33717 this.adapter.setElementSize(this, newSize);
33718 this.fireEvent("moved", this, newSize);
33719 this.fireEvent("resize", this, newSize);
33725 * Get the adapter this SplitBar uses
33726 * @return The adapter object
33728 getAdapter : function(){
33729 return this.adapter;
33733 * Set the adapter this SplitBar uses
33734 * @param {Object} adapter A SplitBar adapter object
33736 setAdapter : function(adapter){
33737 this.adapter = adapter;
33738 this.adapter.init(this);
33742 * Gets the minimum size for the resizing element
33743 * @return {Number} The minimum size
33745 getMinimumSize : function(){
33746 return this.minSize;
33750 * Sets the minimum size for the resizing element
33751 * @param {Number} minSize The minimum size
33753 setMinimumSize : function(minSize){
33754 this.minSize = minSize;
33758 * Gets the maximum size for the resizing element
33759 * @return {Number} The maximum size
33761 getMaximumSize : function(){
33762 return this.maxSize;
33766 * Sets the maximum size for the resizing element
33767 * @param {Number} maxSize The maximum size
33769 setMaximumSize : function(maxSize){
33770 this.maxSize = maxSize;
33774 * Sets the initialize size for the resizing element
33775 * @param {Number} size The initial size
33777 setCurrentSize : function(size){
33778 var oldAnimate = this.animate;
33779 this.animate = false;
33780 this.adapter.setElementSize(this, size);
33781 this.animate = oldAnimate;
33785 * Destroy this splitbar.
33786 * @param {Boolean} removeEl True to remove the element
33788 destroy : function(removeEl){
33790 this.shim.remove();
33793 this.proxy.parentNode.removeChild(this.proxy);
33801 * @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.
33803 Roo.bootstrap.SplitBar.createProxy = function(dir){
33804 var proxy = new Roo.Element(document.createElement("div"));
33805 proxy.unselectable();
33806 var cls = 'roo-splitbar-proxy';
33807 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33808 document.body.appendChild(proxy.dom);
33813 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33814 * Default Adapter. It assumes the splitter and resizing element are not positioned
33815 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33817 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33820 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33821 // do nothing for now
33822 init : function(s){
33826 * Called before drag operations to get the current size of the resizing element.
33827 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33829 getElementSize : function(s){
33830 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33831 return s.resizingEl.getWidth();
33833 return s.resizingEl.getHeight();
33838 * Called after drag operations to set the size of the resizing element.
33839 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33840 * @param {Number} newSize The new size to set
33841 * @param {Function} onComplete A function to be invoked when resizing is complete
33843 setElementSize : function(s, newSize, onComplete){
33844 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33846 s.resizingEl.setWidth(newSize);
33848 onComplete(s, newSize);
33851 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33856 s.resizingEl.setHeight(newSize);
33858 onComplete(s, newSize);
33861 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33868 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33869 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33870 * Adapter that moves the splitter element to align with the resized sizing element.
33871 * Used with an absolute positioned SplitBar.
33872 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33873 * document.body, make sure you assign an id to the body element.
33875 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33876 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33877 this.container = Roo.get(container);
33880 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33881 init : function(s){
33882 this.basic.init(s);
33885 getElementSize : function(s){
33886 return this.basic.getElementSize(s);
33889 setElementSize : function(s, newSize, onComplete){
33890 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33893 moveSplitter : function(s){
33894 var yes = Roo.bootstrap.SplitBar;
33895 switch(s.placement){
33897 s.el.setX(s.resizingEl.getRight());
33900 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33903 s.el.setY(s.resizingEl.getBottom());
33906 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33913 * Orientation constant - Create a vertical SplitBar
33917 Roo.bootstrap.SplitBar.VERTICAL = 1;
33920 * Orientation constant - Create a horizontal SplitBar
33924 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33927 * Placement constant - The resizing element is to the left of the splitter element
33931 Roo.bootstrap.SplitBar.LEFT = 1;
33934 * Placement constant - The resizing element is to the right of the splitter element
33938 Roo.bootstrap.SplitBar.RIGHT = 2;
33941 * Placement constant - The resizing element is positioned above the splitter element
33945 Roo.bootstrap.SplitBar.TOP = 3;
33948 * Placement constant - The resizing element is positioned under splitter element
33952 Roo.bootstrap.SplitBar.BOTTOM = 4;
33953 Roo.namespace("Roo.bootstrap.layout");/*
33955 * Ext JS Library 1.1.1
33956 * Copyright(c) 2006-2007, Ext JS, LLC.
33958 * Originally Released Under LGPL - original licence link has changed is not relivant.
33961 * <script type="text/javascript">
33965 * @class Roo.bootstrap.layout.Manager
33966 * @extends Roo.bootstrap.Component
33967 * Base class for layout managers.
33969 Roo.bootstrap.layout.Manager = function(config)
33971 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33977 /** false to disable window resize monitoring @type Boolean */
33978 this.monitorWindowResize = true;
33983 * Fires when a layout is performed.
33984 * @param {Roo.LayoutManager} this
33988 * @event regionresized
33989 * Fires when the user resizes a region.
33990 * @param {Roo.LayoutRegion} region The resized region
33991 * @param {Number} newSize The new size (width for east/west, height for north/south)
33993 "regionresized" : true,
33995 * @event regioncollapsed
33996 * Fires when a region is collapsed.
33997 * @param {Roo.LayoutRegion} region The collapsed region
33999 "regioncollapsed" : true,
34001 * @event regionexpanded
34002 * Fires when a region is expanded.
34003 * @param {Roo.LayoutRegion} region The expanded region
34005 "regionexpanded" : true
34007 this.updating = false;
34010 this.el = Roo.get(config.el);
34016 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34021 monitorWindowResize : true,
34027 onRender : function(ct, position)
34030 this.el = Roo.get(ct);
34033 //this.fireEvent('render',this);
34037 initEvents: function()
34041 // ie scrollbar fix
34042 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34043 document.body.scroll = "no";
34044 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34045 this.el.position('relative');
34047 this.id = this.el.id;
34048 this.el.addClass("roo-layout-container");
34049 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34050 if(this.el.dom != document.body ) {
34051 this.el.on('resize', this.layout,this);
34052 this.el.on('show', this.layout,this);
34058 * Returns true if this layout is currently being updated
34059 * @return {Boolean}
34061 isUpdating : function(){
34062 return this.updating;
34066 * Suspend the LayoutManager from doing auto-layouts while
34067 * making multiple add or remove calls
34069 beginUpdate : function(){
34070 this.updating = true;
34074 * Restore auto-layouts and optionally disable the manager from performing a layout
34075 * @param {Boolean} noLayout true to disable a layout update
34077 endUpdate : function(noLayout){
34078 this.updating = false;
34084 layout: function(){
34088 onRegionResized : function(region, newSize){
34089 this.fireEvent("regionresized", region, newSize);
34093 onRegionCollapsed : function(region){
34094 this.fireEvent("regioncollapsed", region);
34097 onRegionExpanded : function(region){
34098 this.fireEvent("regionexpanded", region);
34102 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34103 * performs box-model adjustments.
34104 * @return {Object} The size as an object {width: (the width), height: (the height)}
34106 getViewSize : function()
34109 if(this.el.dom != document.body){
34110 size = this.el.getSize();
34112 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34114 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34115 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34120 * Returns the Element this layout is bound to.
34121 * @return {Roo.Element}
34123 getEl : function(){
34128 * Returns the specified region.
34129 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34130 * @return {Roo.LayoutRegion}
34132 getRegion : function(target){
34133 return this.regions[target.toLowerCase()];
34136 onWindowResize : function(){
34137 if(this.monitorWindowResize){
34144 * Ext JS Library 1.1.1
34145 * Copyright(c) 2006-2007, Ext JS, LLC.
34147 * Originally Released Under LGPL - original licence link has changed is not relivant.
34150 * <script type="text/javascript">
34153 * @class Roo.bootstrap.layout.Border
34154 * @extends Roo.bootstrap.layout.Manager
34155 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34156 * please see: examples/bootstrap/nested.html<br><br>
34158 <b>The container the layout is rendered into can be either the body element or any other element.
34159 If it is not the body element, the container needs to either be an absolute positioned element,
34160 or you will need to add "position:relative" to the css of the container. You will also need to specify
34161 the container size if it is not the body element.</b>
34164 * Create a new Border
34165 * @param {Object} config Configuration options
34167 Roo.bootstrap.layout.Border = function(config){
34168 config = config || {};
34169 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34173 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34174 if(config[region]){
34175 config[region].region = region;
34176 this.addRegion(config[region]);
34182 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34184 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34186 * Creates and adds a new region if it doesn't already exist.
34187 * @param {String} target The target region key (north, south, east, west or center).
34188 * @param {Object} config The regions config object
34189 * @return {BorderLayoutRegion} The new region
34191 addRegion : function(config)
34193 if(!this.regions[config.region]){
34194 var r = this.factory(config);
34195 this.bindRegion(r);
34197 return this.regions[config.region];
34201 bindRegion : function(r){
34202 this.regions[r.config.region] = r;
34204 r.on("visibilitychange", this.layout, this);
34205 r.on("paneladded", this.layout, this);
34206 r.on("panelremoved", this.layout, this);
34207 r.on("invalidated", this.layout, this);
34208 r.on("resized", this.onRegionResized, this);
34209 r.on("collapsed", this.onRegionCollapsed, this);
34210 r.on("expanded", this.onRegionExpanded, this);
34214 * Performs a layout update.
34216 layout : function()
34218 if(this.updating) {
34222 // render all the rebions if they have not been done alreayd?
34223 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34224 if(this.regions[region] && !this.regions[region].bodyEl){
34225 this.regions[region].onRender(this.el)
34229 var size = this.getViewSize();
34230 var w = size.width;
34231 var h = size.height;
34236 //var x = 0, y = 0;
34238 var rs = this.regions;
34239 var north = rs["north"];
34240 var south = rs["south"];
34241 var west = rs["west"];
34242 var east = rs["east"];
34243 var center = rs["center"];
34244 //if(this.hideOnLayout){ // not supported anymore
34245 //c.el.setStyle("display", "none");
34247 if(north && north.isVisible()){
34248 var b = north.getBox();
34249 var m = north.getMargins();
34250 b.width = w - (m.left+m.right);
34253 centerY = b.height + b.y + m.bottom;
34254 centerH -= centerY;
34255 north.updateBox(this.safeBox(b));
34257 if(south && south.isVisible()){
34258 var b = south.getBox();
34259 var m = south.getMargins();
34260 b.width = w - (m.left+m.right);
34262 var totalHeight = (b.height + m.top + m.bottom);
34263 b.y = h - totalHeight + m.top;
34264 centerH -= totalHeight;
34265 south.updateBox(this.safeBox(b));
34267 if(west && west.isVisible()){
34268 var b = west.getBox();
34269 var m = west.getMargins();
34270 b.height = centerH - (m.top+m.bottom);
34272 b.y = centerY + m.top;
34273 var totalWidth = (b.width + m.left + m.right);
34274 centerX += totalWidth;
34275 centerW -= totalWidth;
34276 west.updateBox(this.safeBox(b));
34278 if(east && east.isVisible()){
34279 var b = east.getBox();
34280 var m = east.getMargins();
34281 b.height = centerH - (m.top+m.bottom);
34282 var totalWidth = (b.width + m.left + m.right);
34283 b.x = w - totalWidth + m.left;
34284 b.y = centerY + m.top;
34285 centerW -= totalWidth;
34286 east.updateBox(this.safeBox(b));
34289 var m = center.getMargins();
34291 x: centerX + m.left,
34292 y: centerY + m.top,
34293 width: centerW - (m.left+m.right),
34294 height: centerH - (m.top+m.bottom)
34296 //if(this.hideOnLayout){
34297 //center.el.setStyle("display", "block");
34299 center.updateBox(this.safeBox(centerBox));
34302 this.fireEvent("layout", this);
34306 safeBox : function(box){
34307 box.width = Math.max(0, box.width);
34308 box.height = Math.max(0, box.height);
34313 * Adds a ContentPanel (or subclass) to this layout.
34314 * @param {String} target The target region key (north, south, east, west or center).
34315 * @param {Roo.ContentPanel} panel The panel to add
34316 * @return {Roo.ContentPanel} The added panel
34318 add : function(target, panel){
34320 target = target.toLowerCase();
34321 return this.regions[target].add(panel);
34325 * Remove a ContentPanel (or subclass) to this layout.
34326 * @param {String} target The target region key (north, south, east, west or center).
34327 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34328 * @return {Roo.ContentPanel} The removed panel
34330 remove : function(target, panel){
34331 target = target.toLowerCase();
34332 return this.regions[target].remove(panel);
34336 * Searches all regions for a panel with the specified id
34337 * @param {String} panelId
34338 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34340 findPanel : function(panelId){
34341 var rs = this.regions;
34342 for(var target in rs){
34343 if(typeof rs[target] != "function"){
34344 var p = rs[target].getPanel(panelId);
34354 * Searches all regions for a panel with the specified id and activates (shows) it.
34355 * @param {String/ContentPanel} panelId The panels id or the panel itself
34356 * @return {Roo.ContentPanel} The shown panel or null
34358 showPanel : function(panelId) {
34359 var rs = this.regions;
34360 for(var target in rs){
34361 var r = rs[target];
34362 if(typeof r != "function"){
34363 if(r.hasPanel(panelId)){
34364 return r.showPanel(panelId);
34372 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34373 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34376 restoreState : function(provider){
34378 provider = Roo.state.Manager;
34380 var sm = new Roo.LayoutStateManager();
34381 sm.init(this, provider);
34387 * Adds a xtype elements to the layout.
34391 xtype : 'ContentPanel',
34398 xtype : 'NestedLayoutPanel',
34404 items : [ ... list of content panels or nested layout panels.. ]
34408 * @param {Object} cfg Xtype definition of item to add.
34410 addxtype : function(cfg)
34412 // basically accepts a pannel...
34413 // can accept a layout region..!?!?
34414 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34417 // theory? children can only be panels??
34419 //if (!cfg.xtype.match(/Panel$/)) {
34424 if (typeof(cfg.region) == 'undefined') {
34425 Roo.log("Failed to add Panel, region was not set");
34429 var region = cfg.region;
34435 xitems = cfg.items;
34442 case 'Content': // ContentPanel (el, cfg)
34443 case 'Scroll': // ContentPanel (el, cfg)
34445 cfg.autoCreate = true;
34446 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34448 // var el = this.el.createChild();
34449 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34452 this.add(region, ret);
34456 case 'TreePanel': // our new panel!
34457 cfg.el = this.el.createChild();
34458 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34459 this.add(region, ret);
34464 // create a new Layout (which is a Border Layout...
34466 var clayout = cfg.layout;
34467 clayout.el = this.el.createChild();
34468 clayout.items = clayout.items || [];
34472 // replace this exitems with the clayout ones..
34473 xitems = clayout.items;
34475 // force background off if it's in center...
34476 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34477 cfg.background = false;
34479 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34482 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34483 //console.log('adding nested layout panel ' + cfg.toSource());
34484 this.add(region, ret);
34485 nb = {}; /// find first...
34490 // needs grid and region
34492 //var el = this.getRegion(region).el.createChild();
34494 *var el = this.el.createChild();
34495 // create the grid first...
34496 cfg.grid.container = el;
34497 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34500 if (region == 'center' && this.active ) {
34501 cfg.background = false;
34504 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34506 this.add(region, ret);
34508 if (cfg.background) {
34509 // render grid on panel activation (if panel background)
34510 ret.on('activate', function(gp) {
34511 if (!gp.grid.rendered) {
34512 // gp.grid.render(el);
34516 // cfg.grid.render(el);
34522 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34523 // it was the old xcomponent building that caused this before.
34524 // espeically if border is the top element in the tree.
34534 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34536 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34537 this.add(region, ret);
34541 throw "Can not add '" + cfg.xtype + "' to Border";
34547 this.beginUpdate();
34551 Roo.each(xitems, function(i) {
34552 region = nb && i.region ? i.region : false;
34554 var add = ret.addxtype(i);
34557 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34558 if (!i.background) {
34559 abn[region] = nb[region] ;
34566 // make the last non-background panel active..
34567 //if (nb) { Roo.log(abn); }
34570 for(var r in abn) {
34571 region = this.getRegion(r);
34573 // tried using nb[r], but it does not work..
34575 region.showPanel(abn[r]);
34586 factory : function(cfg)
34589 var validRegions = Roo.bootstrap.layout.Border.regions;
34591 var target = cfg.region;
34594 var r = Roo.bootstrap.layout;
34598 return new r.North(cfg);
34600 return new r.South(cfg);
34602 return new r.East(cfg);
34604 return new r.West(cfg);
34606 return new r.Center(cfg);
34608 throw 'Layout region "'+target+'" not supported.';
34615 * Ext JS Library 1.1.1
34616 * Copyright(c) 2006-2007, Ext JS, LLC.
34618 * Originally Released Under LGPL - original licence link has changed is not relivant.
34621 * <script type="text/javascript">
34625 * @class Roo.bootstrap.layout.Basic
34626 * @extends Roo.util.Observable
34627 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34628 * and does not have a titlebar, tabs or any other features. All it does is size and position
34629 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34630 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34631 * @cfg {string} region the region that it inhabits..
34632 * @cfg {bool} skipConfig skip config?
34636 Roo.bootstrap.layout.Basic = function(config){
34638 this.mgr = config.mgr;
34640 this.position = config.region;
34642 var skipConfig = config.skipConfig;
34646 * @scope Roo.BasicLayoutRegion
34650 * @event beforeremove
34651 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34652 * @param {Roo.LayoutRegion} this
34653 * @param {Roo.ContentPanel} panel The panel
34654 * @param {Object} e The cancel event object
34656 "beforeremove" : true,
34658 * @event invalidated
34659 * Fires when the layout for this region is changed.
34660 * @param {Roo.LayoutRegion} this
34662 "invalidated" : true,
34664 * @event visibilitychange
34665 * Fires when this region is shown or hidden
34666 * @param {Roo.LayoutRegion} this
34667 * @param {Boolean} visibility true or false
34669 "visibilitychange" : true,
34671 * @event paneladded
34672 * Fires when a panel is added.
34673 * @param {Roo.LayoutRegion} this
34674 * @param {Roo.ContentPanel} panel The panel
34676 "paneladded" : true,
34678 * @event panelremoved
34679 * Fires when a panel is removed.
34680 * @param {Roo.LayoutRegion} this
34681 * @param {Roo.ContentPanel} panel The panel
34683 "panelremoved" : true,
34685 * @event beforecollapse
34686 * Fires when this region before collapse.
34687 * @param {Roo.LayoutRegion} this
34689 "beforecollapse" : true,
34692 * Fires when this region is collapsed.
34693 * @param {Roo.LayoutRegion} this
34695 "collapsed" : true,
34698 * Fires when this region is expanded.
34699 * @param {Roo.LayoutRegion} this
34704 * Fires when this region is slid into view.
34705 * @param {Roo.LayoutRegion} this
34707 "slideshow" : true,
34710 * Fires when this region slides out of view.
34711 * @param {Roo.LayoutRegion} this
34713 "slidehide" : true,
34715 * @event panelactivated
34716 * Fires when a panel is activated.
34717 * @param {Roo.LayoutRegion} this
34718 * @param {Roo.ContentPanel} panel The activated panel
34720 "panelactivated" : true,
34723 * Fires when the user resizes this region.
34724 * @param {Roo.LayoutRegion} this
34725 * @param {Number} newSize The new size (width for east/west, height for north/south)
34729 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34730 this.panels = new Roo.util.MixedCollection();
34731 this.panels.getKey = this.getPanelId.createDelegate(this);
34733 this.activePanel = null;
34734 // ensure listeners are added...
34736 if (config.listeners || config.events) {
34737 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34738 listeners : config.listeners || {},
34739 events : config.events || {}
34743 if(skipConfig !== true){
34744 this.applyConfig(config);
34748 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34750 getPanelId : function(p){
34754 applyConfig : function(config){
34755 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34756 this.config = config;
34761 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34762 * the width, for horizontal (north, south) the height.
34763 * @param {Number} newSize The new width or height
34765 resizeTo : function(newSize){
34766 var el = this.el ? this.el :
34767 (this.activePanel ? this.activePanel.getEl() : null);
34769 switch(this.position){
34772 el.setWidth(newSize);
34773 this.fireEvent("resized", this, newSize);
34777 el.setHeight(newSize);
34778 this.fireEvent("resized", this, newSize);
34784 getBox : function(){
34785 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34788 getMargins : function(){
34789 return this.margins;
34792 updateBox : function(box){
34794 var el = this.activePanel.getEl();
34795 el.dom.style.left = box.x + "px";
34796 el.dom.style.top = box.y + "px";
34797 this.activePanel.setSize(box.width, box.height);
34801 * Returns the container element for this region.
34802 * @return {Roo.Element}
34804 getEl : function(){
34805 return this.activePanel;
34809 * Returns true if this region is currently visible.
34810 * @return {Boolean}
34812 isVisible : function(){
34813 return this.activePanel ? true : false;
34816 setActivePanel : function(panel){
34817 panel = this.getPanel(panel);
34818 if(this.activePanel && this.activePanel != panel){
34819 this.activePanel.setActiveState(false);
34820 this.activePanel.getEl().setLeftTop(-10000,-10000);
34822 this.activePanel = panel;
34823 panel.setActiveState(true);
34825 panel.setSize(this.box.width, this.box.height);
34827 this.fireEvent("panelactivated", this, panel);
34828 this.fireEvent("invalidated");
34832 * Show the specified panel.
34833 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34834 * @return {Roo.ContentPanel} The shown panel or null
34836 showPanel : function(panel){
34837 panel = this.getPanel(panel);
34839 this.setActivePanel(panel);
34845 * Get the active panel for this region.
34846 * @return {Roo.ContentPanel} The active panel or null
34848 getActivePanel : function(){
34849 return this.activePanel;
34853 * Add the passed ContentPanel(s)
34854 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34855 * @return {Roo.ContentPanel} The panel added (if only one was added)
34857 add : function(panel){
34858 if(arguments.length > 1){
34859 for(var i = 0, len = arguments.length; i < len; i++) {
34860 this.add(arguments[i]);
34864 if(this.hasPanel(panel)){
34865 this.showPanel(panel);
34868 var el = panel.getEl();
34869 if(el.dom.parentNode != this.mgr.el.dom){
34870 this.mgr.el.dom.appendChild(el.dom);
34872 if(panel.setRegion){
34873 panel.setRegion(this);
34875 this.panels.add(panel);
34876 el.setStyle("position", "absolute");
34877 if(!panel.background){
34878 this.setActivePanel(panel);
34879 if(this.config.initialSize && this.panels.getCount()==1){
34880 this.resizeTo(this.config.initialSize);
34883 this.fireEvent("paneladded", this, panel);
34888 * Returns true if the panel is in this region.
34889 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34890 * @return {Boolean}
34892 hasPanel : function(panel){
34893 if(typeof panel == "object"){ // must be panel obj
34894 panel = panel.getId();
34896 return this.getPanel(panel) ? true : false;
34900 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34901 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34902 * @param {Boolean} preservePanel Overrides the config preservePanel option
34903 * @return {Roo.ContentPanel} The panel that was removed
34905 remove : function(panel, preservePanel){
34906 panel = this.getPanel(panel);
34911 this.fireEvent("beforeremove", this, panel, e);
34912 if(e.cancel === true){
34915 var panelId = panel.getId();
34916 this.panels.removeKey(panelId);
34921 * Returns the panel specified or null if it's not in this region.
34922 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34923 * @return {Roo.ContentPanel}
34925 getPanel : function(id){
34926 if(typeof id == "object"){ // must be panel obj
34929 return this.panels.get(id);
34933 * Returns this regions position (north/south/east/west/center).
34936 getPosition: function(){
34937 return this.position;
34941 * Ext JS Library 1.1.1
34942 * Copyright(c) 2006-2007, Ext JS, LLC.
34944 * Originally Released Under LGPL - original licence link has changed is not relivant.
34947 * <script type="text/javascript">
34951 * @class Roo.bootstrap.layout.Region
34952 * @extends Roo.bootstrap.layout.Basic
34953 * This class represents a region in a layout manager.
34955 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34956 * @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})
34957 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34958 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34959 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34960 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34961 * @cfg {String} title The title for the region (overrides panel titles)
34962 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34963 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34964 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34965 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34966 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34967 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34968 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34969 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34970 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34971 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34973 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34974 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34975 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34976 * @cfg {Number} width For East/West panels
34977 * @cfg {Number} height For North/South panels
34978 * @cfg {Boolean} split To show the splitter
34979 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34981 * @cfg {string} cls Extra CSS classes to add to region
34983 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34984 * @cfg {string} region the region that it inhabits..
34987 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34988 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34990 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34991 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34992 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34994 Roo.bootstrap.layout.Region = function(config)
34996 this.applyConfig(config);
34998 var mgr = config.mgr;
34999 var pos = config.region;
35000 config.skipConfig = true;
35001 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35004 this.onRender(mgr.el);
35007 this.visible = true;
35008 this.collapsed = false;
35009 this.unrendered_panels = [];
35012 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35014 position: '', // set by wrapper (eg. north/south etc..)
35015 unrendered_panels : null, // unrendered panels.
35016 createBody : function(){
35017 /** This region's body element
35018 * @type Roo.Element */
35019 this.bodyEl = this.el.createChild({
35021 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35025 onRender: function(ctr, pos)
35027 var dh = Roo.DomHelper;
35028 /** This region's container element
35029 * @type Roo.Element */
35030 this.el = dh.append(ctr.dom, {
35032 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35034 /** This region's title element
35035 * @type Roo.Element */
35037 this.titleEl = dh.append(this.el.dom,
35040 unselectable: "on",
35041 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35043 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35044 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35047 this.titleEl.enableDisplayMode();
35048 /** This region's title text element
35049 * @type HTMLElement */
35050 this.titleTextEl = this.titleEl.dom.firstChild;
35051 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35053 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35054 this.closeBtn.enableDisplayMode();
35055 this.closeBtn.on("click", this.closeClicked, this);
35056 this.closeBtn.hide();
35058 this.createBody(this.config);
35059 if(this.config.hideWhenEmpty){
35061 this.on("paneladded", this.validateVisibility, this);
35062 this.on("panelremoved", this.validateVisibility, this);
35064 if(this.autoScroll){
35065 this.bodyEl.setStyle("overflow", "auto");
35067 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35069 //if(c.titlebar !== false){
35070 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35071 this.titleEl.hide();
35073 this.titleEl.show();
35074 if(this.config.title){
35075 this.titleTextEl.innerHTML = this.config.title;
35079 if(this.config.collapsed){
35080 this.collapse(true);
35082 if(this.config.hidden){
35086 if (this.unrendered_panels && this.unrendered_panels.length) {
35087 for (var i =0;i< this.unrendered_panels.length; i++) {
35088 this.add(this.unrendered_panels[i]);
35090 this.unrendered_panels = null;
35096 applyConfig : function(c)
35099 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35100 var dh = Roo.DomHelper;
35101 if(c.titlebar !== false){
35102 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35103 this.collapseBtn.on("click", this.collapse, this);
35104 this.collapseBtn.enableDisplayMode();
35106 if(c.showPin === true || this.showPin){
35107 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35108 this.stickBtn.enableDisplayMode();
35109 this.stickBtn.on("click", this.expand, this);
35110 this.stickBtn.hide();
35115 /** This region's collapsed element
35116 * @type Roo.Element */
35119 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35120 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35123 if(c.floatable !== false){
35124 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35125 this.collapsedEl.on("click", this.collapseClick, this);
35128 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35129 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35130 id: "message", unselectable: "on", style:{"float":"left"}});
35131 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35133 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35134 this.expandBtn.on("click", this.expand, this);
35138 if(this.collapseBtn){
35139 this.collapseBtn.setVisible(c.collapsible == true);
35142 this.cmargins = c.cmargins || this.cmargins ||
35143 (this.position == "west" || this.position == "east" ?
35144 {top: 0, left: 2, right:2, bottom: 0} :
35145 {top: 2, left: 0, right:0, bottom: 2});
35147 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35150 this.bottomTabs = c.tabPosition != "top";
35152 this.autoScroll = c.autoScroll || false;
35157 this.duration = c.duration || .30;
35158 this.slideDuration = c.slideDuration || .45;
35163 * Returns true if this region is currently visible.
35164 * @return {Boolean}
35166 isVisible : function(){
35167 return this.visible;
35171 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35172 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35174 //setCollapsedTitle : function(title){
35175 // title = title || " ";
35176 // if(this.collapsedTitleTextEl){
35177 // this.collapsedTitleTextEl.innerHTML = title;
35181 getBox : function(){
35183 // if(!this.collapsed){
35184 b = this.el.getBox(false, true);
35186 // b = this.collapsedEl.getBox(false, true);
35191 getMargins : function(){
35192 return this.margins;
35193 //return this.collapsed ? this.cmargins : this.margins;
35196 highlight : function(){
35197 this.el.addClass("x-layout-panel-dragover");
35200 unhighlight : function(){
35201 this.el.removeClass("x-layout-panel-dragover");
35204 updateBox : function(box)
35206 if (!this.bodyEl) {
35207 return; // not rendered yet..
35211 if(!this.collapsed){
35212 this.el.dom.style.left = box.x + "px";
35213 this.el.dom.style.top = box.y + "px";
35214 this.updateBody(box.width, box.height);
35216 this.collapsedEl.dom.style.left = box.x + "px";
35217 this.collapsedEl.dom.style.top = box.y + "px";
35218 this.collapsedEl.setSize(box.width, box.height);
35221 this.tabs.autoSizeTabs();
35225 updateBody : function(w, h)
35228 this.el.setWidth(w);
35229 w -= this.el.getBorderWidth("rl");
35230 if(this.config.adjustments){
35231 w += this.config.adjustments[0];
35234 if(h !== null && h > 0){
35235 this.el.setHeight(h);
35236 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35237 h -= this.el.getBorderWidth("tb");
35238 if(this.config.adjustments){
35239 h += this.config.adjustments[1];
35241 this.bodyEl.setHeight(h);
35243 h = this.tabs.syncHeight(h);
35246 if(this.panelSize){
35247 w = w !== null ? w : this.panelSize.width;
35248 h = h !== null ? h : this.panelSize.height;
35250 if(this.activePanel){
35251 var el = this.activePanel.getEl();
35252 w = w !== null ? w : el.getWidth();
35253 h = h !== null ? h : el.getHeight();
35254 this.panelSize = {width: w, height: h};
35255 this.activePanel.setSize(w, h);
35257 if(Roo.isIE && this.tabs){
35258 this.tabs.el.repaint();
35263 * Returns the container element for this region.
35264 * @return {Roo.Element}
35266 getEl : function(){
35271 * Hides this region.
35274 //if(!this.collapsed){
35275 this.el.dom.style.left = "-2000px";
35278 // this.collapsedEl.dom.style.left = "-2000px";
35279 // this.collapsedEl.hide();
35281 this.visible = false;
35282 this.fireEvent("visibilitychange", this, false);
35286 * Shows this region if it was previously hidden.
35289 //if(!this.collapsed){
35292 // this.collapsedEl.show();
35294 this.visible = true;
35295 this.fireEvent("visibilitychange", this, true);
35298 closeClicked : function(){
35299 if(this.activePanel){
35300 this.remove(this.activePanel);
35304 collapseClick : function(e){
35306 e.stopPropagation();
35309 e.stopPropagation();
35315 * Collapses this region.
35316 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35319 collapse : function(skipAnim, skipCheck = false){
35320 if(this.collapsed) {
35324 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35326 this.collapsed = true;
35328 this.split.el.hide();
35330 if(this.config.animate && skipAnim !== true){
35331 this.fireEvent("invalidated", this);
35332 this.animateCollapse();
35334 this.el.setLocation(-20000,-20000);
35336 this.collapsedEl.show();
35337 this.fireEvent("collapsed", this);
35338 this.fireEvent("invalidated", this);
35344 animateCollapse : function(){
35349 * Expands this region if it was previously collapsed.
35350 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35351 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35354 expand : function(e, skipAnim){
35356 e.stopPropagation();
35358 if(!this.collapsed || this.el.hasActiveFx()) {
35362 this.afterSlideIn();
35365 this.collapsed = false;
35366 if(this.config.animate && skipAnim !== true){
35367 this.animateExpand();
35371 this.split.el.show();
35373 this.collapsedEl.setLocation(-2000,-2000);
35374 this.collapsedEl.hide();
35375 this.fireEvent("invalidated", this);
35376 this.fireEvent("expanded", this);
35380 animateExpand : function(){
35384 initTabs : function()
35386 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35388 var ts = new Roo.bootstrap.panel.Tabs({
35389 el: this.bodyEl.dom,
35390 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35391 disableTooltips: this.config.disableTabTips,
35392 toolbar : this.config.toolbar
35395 if(this.config.hideTabs){
35396 ts.stripWrap.setDisplayed(false);
35399 ts.resizeTabs = this.config.resizeTabs === true;
35400 ts.minTabWidth = this.config.minTabWidth || 40;
35401 ts.maxTabWidth = this.config.maxTabWidth || 250;
35402 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35403 ts.monitorResize = false;
35404 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35405 ts.bodyEl.addClass('roo-layout-tabs-body');
35406 this.panels.each(this.initPanelAsTab, this);
35409 initPanelAsTab : function(panel){
35410 var ti = this.tabs.addTab(
35414 this.config.closeOnTab && panel.isClosable(),
35417 if(panel.tabTip !== undefined){
35418 ti.setTooltip(panel.tabTip);
35420 ti.on("activate", function(){
35421 this.setActivePanel(panel);
35424 if(this.config.closeOnTab){
35425 ti.on("beforeclose", function(t, e){
35427 this.remove(panel);
35431 panel.tabItem = ti;
35436 updatePanelTitle : function(panel, title)
35438 if(this.activePanel == panel){
35439 this.updateTitle(title);
35442 var ti = this.tabs.getTab(panel.getEl().id);
35444 if(panel.tabTip !== undefined){
35445 ti.setTooltip(panel.tabTip);
35450 updateTitle : function(title){
35451 if(this.titleTextEl && !this.config.title){
35452 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35456 setActivePanel : function(panel)
35458 panel = this.getPanel(panel);
35459 if(this.activePanel && this.activePanel != panel){
35460 if(this.activePanel.setActiveState(false) === false){
35464 this.activePanel = panel;
35465 panel.setActiveState(true);
35466 if(this.panelSize){
35467 panel.setSize(this.panelSize.width, this.panelSize.height);
35470 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35472 this.updateTitle(panel.getTitle());
35474 this.fireEvent("invalidated", this);
35476 this.fireEvent("panelactivated", this, panel);
35480 * Shows the specified panel.
35481 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35482 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35484 showPanel : function(panel)
35486 panel = this.getPanel(panel);
35489 var tab = this.tabs.getTab(panel.getEl().id);
35490 if(tab.isHidden()){
35491 this.tabs.unhideTab(tab.id);
35495 this.setActivePanel(panel);
35502 * Get the active panel for this region.
35503 * @return {Roo.ContentPanel} The active panel or null
35505 getActivePanel : function(){
35506 return this.activePanel;
35509 validateVisibility : function(){
35510 if(this.panels.getCount() < 1){
35511 this.updateTitle(" ");
35512 this.closeBtn.hide();
35515 if(!this.isVisible()){
35522 * Adds the passed ContentPanel(s) to this region.
35523 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35524 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35526 add : function(panel)
35528 if(arguments.length > 1){
35529 for(var i = 0, len = arguments.length; i < len; i++) {
35530 this.add(arguments[i]);
35535 // if we have not been rendered yet, then we can not really do much of this..
35536 if (!this.bodyEl) {
35537 this.unrendered_panels.push(panel);
35544 if(this.hasPanel(panel)){
35545 this.showPanel(panel);
35548 panel.setRegion(this);
35549 this.panels.add(panel);
35550 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35551 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35552 // and hide them... ???
35553 this.bodyEl.dom.appendChild(panel.getEl().dom);
35554 if(panel.background !== true){
35555 this.setActivePanel(panel);
35557 this.fireEvent("paneladded", this, panel);
35564 this.initPanelAsTab(panel);
35568 if(panel.background !== true){
35569 this.tabs.activate(panel.getEl().id);
35571 this.fireEvent("paneladded", this, panel);
35576 * Hides the tab for the specified panel.
35577 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35579 hidePanel : function(panel){
35580 if(this.tabs && (panel = this.getPanel(panel))){
35581 this.tabs.hideTab(panel.getEl().id);
35586 * Unhides the tab for a previously hidden panel.
35587 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35589 unhidePanel : function(panel){
35590 if(this.tabs && (panel = this.getPanel(panel))){
35591 this.tabs.unhideTab(panel.getEl().id);
35595 clearPanels : function(){
35596 while(this.panels.getCount() > 0){
35597 this.remove(this.panels.first());
35602 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35603 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35604 * @param {Boolean} preservePanel Overrides the config preservePanel option
35605 * @return {Roo.ContentPanel} The panel that was removed
35607 remove : function(panel, preservePanel)
35609 panel = this.getPanel(panel);
35614 this.fireEvent("beforeremove", this, panel, e);
35615 if(e.cancel === true){
35618 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35619 var panelId = panel.getId();
35620 this.panels.removeKey(panelId);
35622 document.body.appendChild(panel.getEl().dom);
35625 this.tabs.removeTab(panel.getEl().id);
35626 }else if (!preservePanel){
35627 this.bodyEl.dom.removeChild(panel.getEl().dom);
35629 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35630 var p = this.panels.first();
35631 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35632 tempEl.appendChild(p.getEl().dom);
35633 this.bodyEl.update("");
35634 this.bodyEl.dom.appendChild(p.getEl().dom);
35636 this.updateTitle(p.getTitle());
35638 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35639 this.setActivePanel(p);
35641 panel.setRegion(null);
35642 if(this.activePanel == panel){
35643 this.activePanel = null;
35645 if(this.config.autoDestroy !== false && preservePanel !== true){
35646 try{panel.destroy();}catch(e){}
35648 this.fireEvent("panelremoved", this, panel);
35653 * Returns the TabPanel component used by this region
35654 * @return {Roo.TabPanel}
35656 getTabs : function(){
35660 createTool : function(parentEl, className){
35661 var btn = Roo.DomHelper.append(parentEl, {
35663 cls: "x-layout-tools-button",
35666 cls: "roo-layout-tools-button-inner " + className,
35670 btn.addClassOnOver("roo-layout-tools-button-over");
35675 * Ext JS Library 1.1.1
35676 * Copyright(c) 2006-2007, Ext JS, LLC.
35678 * Originally Released Under LGPL - original licence link has changed is not relivant.
35681 * <script type="text/javascript">
35687 * @class Roo.SplitLayoutRegion
35688 * @extends Roo.LayoutRegion
35689 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35691 Roo.bootstrap.layout.Split = function(config){
35692 this.cursor = config.cursor;
35693 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35696 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35698 splitTip : "Drag to resize.",
35699 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35700 useSplitTips : false,
35702 applyConfig : function(config){
35703 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35706 onRender : function(ctr,pos) {
35708 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35709 if(!this.config.split){
35714 var splitEl = Roo.DomHelper.append(ctr.dom, {
35716 id: this.el.id + "-split",
35717 cls: "roo-layout-split roo-layout-split-"+this.position,
35720 /** The SplitBar for this region
35721 * @type Roo.SplitBar */
35722 // does not exist yet...
35723 Roo.log([this.position, this.orientation]);
35725 this.split = new Roo.bootstrap.SplitBar({
35726 dragElement : splitEl,
35727 resizingElement: this.el,
35728 orientation : this.orientation
35731 this.split.on("moved", this.onSplitMove, this);
35732 this.split.useShim = this.config.useShim === true;
35733 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35734 if(this.useSplitTips){
35735 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35737 //if(config.collapsible){
35738 // this.split.el.on("dblclick", this.collapse, this);
35741 if(typeof this.config.minSize != "undefined"){
35742 this.split.minSize = this.config.minSize;
35744 if(typeof this.config.maxSize != "undefined"){
35745 this.split.maxSize = this.config.maxSize;
35747 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35748 this.hideSplitter();
35753 getHMaxSize : function(){
35754 var cmax = this.config.maxSize || 10000;
35755 var center = this.mgr.getRegion("center");
35756 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35759 getVMaxSize : function(){
35760 var cmax = this.config.maxSize || 10000;
35761 var center = this.mgr.getRegion("center");
35762 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35765 onSplitMove : function(split, newSize){
35766 this.fireEvent("resized", this, newSize);
35770 * Returns the {@link Roo.SplitBar} for this region.
35771 * @return {Roo.SplitBar}
35773 getSplitBar : function(){
35778 this.hideSplitter();
35779 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35782 hideSplitter : function(){
35784 this.split.el.setLocation(-2000,-2000);
35785 this.split.el.hide();
35791 this.split.el.show();
35793 Roo.bootstrap.layout.Split.superclass.show.call(this);
35796 beforeSlide: function(){
35797 if(Roo.isGecko){// firefox overflow auto bug workaround
35798 this.bodyEl.clip();
35800 this.tabs.bodyEl.clip();
35802 if(this.activePanel){
35803 this.activePanel.getEl().clip();
35805 if(this.activePanel.beforeSlide){
35806 this.activePanel.beforeSlide();
35812 afterSlide : function(){
35813 if(Roo.isGecko){// firefox overflow auto bug workaround
35814 this.bodyEl.unclip();
35816 this.tabs.bodyEl.unclip();
35818 if(this.activePanel){
35819 this.activePanel.getEl().unclip();
35820 if(this.activePanel.afterSlide){
35821 this.activePanel.afterSlide();
35827 initAutoHide : function(){
35828 if(this.autoHide !== false){
35829 if(!this.autoHideHd){
35830 var st = new Roo.util.DelayedTask(this.slideIn, this);
35831 this.autoHideHd = {
35832 "mouseout": function(e){
35833 if(!e.within(this.el, true)){
35837 "mouseover" : function(e){
35843 this.el.on(this.autoHideHd);
35847 clearAutoHide : function(){
35848 if(this.autoHide !== false){
35849 this.el.un("mouseout", this.autoHideHd.mouseout);
35850 this.el.un("mouseover", this.autoHideHd.mouseover);
35854 clearMonitor : function(){
35855 Roo.get(document).un("click", this.slideInIf, this);
35858 // these names are backwards but not changed for compat
35859 slideOut : function(){
35860 if(this.isSlid || this.el.hasActiveFx()){
35863 this.isSlid = true;
35864 if(this.collapseBtn){
35865 this.collapseBtn.hide();
35867 this.closeBtnState = this.closeBtn.getStyle('display');
35868 this.closeBtn.hide();
35870 this.stickBtn.show();
35873 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35874 this.beforeSlide();
35875 this.el.setStyle("z-index", 10001);
35876 this.el.slideIn(this.getSlideAnchor(), {
35877 callback: function(){
35879 this.initAutoHide();
35880 Roo.get(document).on("click", this.slideInIf, this);
35881 this.fireEvent("slideshow", this);
35888 afterSlideIn : function(){
35889 this.clearAutoHide();
35890 this.isSlid = false;
35891 this.clearMonitor();
35892 this.el.setStyle("z-index", "");
35893 if(this.collapseBtn){
35894 this.collapseBtn.show();
35896 this.closeBtn.setStyle('display', this.closeBtnState);
35898 this.stickBtn.hide();
35900 this.fireEvent("slidehide", this);
35903 slideIn : function(cb){
35904 if(!this.isSlid || this.el.hasActiveFx()){
35908 this.isSlid = false;
35909 this.beforeSlide();
35910 this.el.slideOut(this.getSlideAnchor(), {
35911 callback: function(){
35912 this.el.setLeftTop(-10000, -10000);
35914 this.afterSlideIn();
35922 slideInIf : function(e){
35923 if(!e.within(this.el)){
35928 animateCollapse : function(){
35929 this.beforeSlide();
35930 this.el.setStyle("z-index", 20000);
35931 var anchor = this.getSlideAnchor();
35932 this.el.slideOut(anchor, {
35933 callback : function(){
35934 this.el.setStyle("z-index", "");
35935 this.collapsedEl.slideIn(anchor, {duration:.3});
35937 this.el.setLocation(-10000,-10000);
35939 this.fireEvent("collapsed", this);
35946 animateExpand : function(){
35947 this.beforeSlide();
35948 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35949 this.el.setStyle("z-index", 20000);
35950 this.collapsedEl.hide({
35953 this.el.slideIn(this.getSlideAnchor(), {
35954 callback : function(){
35955 this.el.setStyle("z-index", "");
35958 this.split.el.show();
35960 this.fireEvent("invalidated", this);
35961 this.fireEvent("expanded", this);
35989 getAnchor : function(){
35990 return this.anchors[this.position];
35993 getCollapseAnchor : function(){
35994 return this.canchors[this.position];
35997 getSlideAnchor : function(){
35998 return this.sanchors[this.position];
36001 getAlignAdj : function(){
36002 var cm = this.cmargins;
36003 switch(this.position){
36019 getExpandAdj : function(){
36020 var c = this.collapsedEl, cm = this.cmargins;
36021 switch(this.position){
36023 return [-(cm.right+c.getWidth()+cm.left), 0];
36026 return [cm.right+c.getWidth()+cm.left, 0];
36029 return [0, -(cm.top+cm.bottom+c.getHeight())];
36032 return [0, cm.top+cm.bottom+c.getHeight()];
36038 * Ext JS Library 1.1.1
36039 * Copyright(c) 2006-2007, Ext JS, LLC.
36041 * Originally Released Under LGPL - original licence link has changed is not relivant.
36044 * <script type="text/javascript">
36047 * These classes are private internal classes
36049 Roo.bootstrap.layout.Center = function(config){
36050 config.region = "center";
36051 Roo.bootstrap.layout.Region.call(this, config);
36052 this.visible = true;
36053 this.minWidth = config.minWidth || 20;
36054 this.minHeight = config.minHeight || 20;
36057 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36059 // center panel can't be hidden
36063 // center panel can't be hidden
36066 getMinWidth: function(){
36067 return this.minWidth;
36070 getMinHeight: function(){
36071 return this.minHeight;
36084 Roo.bootstrap.layout.North = function(config)
36086 config.region = 'north';
36087 config.cursor = 'n-resize';
36089 Roo.bootstrap.layout.Split.call(this, config);
36093 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36094 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36095 this.split.el.addClass("roo-layout-split-v");
36097 var size = config.initialSize || config.height;
36098 if(typeof size != "undefined"){
36099 this.el.setHeight(size);
36102 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36104 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36108 getBox : function(){
36109 if(this.collapsed){
36110 return this.collapsedEl.getBox();
36112 var box = this.el.getBox();
36114 box.height += this.split.el.getHeight();
36119 updateBox : function(box){
36120 if(this.split && !this.collapsed){
36121 box.height -= this.split.el.getHeight();
36122 this.split.el.setLeft(box.x);
36123 this.split.el.setTop(box.y+box.height);
36124 this.split.el.setWidth(box.width);
36126 if(this.collapsed){
36127 this.updateBody(box.width, null);
36129 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36137 Roo.bootstrap.layout.South = function(config){
36138 config.region = 'south';
36139 config.cursor = 's-resize';
36140 Roo.bootstrap.layout.Split.call(this, config);
36142 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36143 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36144 this.split.el.addClass("roo-layout-split-v");
36146 var size = config.initialSize || config.height;
36147 if(typeof size != "undefined"){
36148 this.el.setHeight(size);
36152 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36153 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36154 getBox : function(){
36155 if(this.collapsed){
36156 return this.collapsedEl.getBox();
36158 var box = this.el.getBox();
36160 var sh = this.split.el.getHeight();
36167 updateBox : function(box){
36168 if(this.split && !this.collapsed){
36169 var sh = this.split.el.getHeight();
36172 this.split.el.setLeft(box.x);
36173 this.split.el.setTop(box.y-sh);
36174 this.split.el.setWidth(box.width);
36176 if(this.collapsed){
36177 this.updateBody(box.width, null);
36179 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36183 Roo.bootstrap.layout.East = function(config){
36184 config.region = "east";
36185 config.cursor = "e-resize";
36186 Roo.bootstrap.layout.Split.call(this, config);
36188 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36189 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36190 this.split.el.addClass("roo-layout-split-h");
36192 var size = config.initialSize || config.width;
36193 if(typeof size != "undefined"){
36194 this.el.setWidth(size);
36197 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36198 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36199 getBox : function(){
36200 if(this.collapsed){
36201 return this.collapsedEl.getBox();
36203 var box = this.el.getBox();
36205 var sw = this.split.el.getWidth();
36212 updateBox : function(box){
36213 if(this.split && !this.collapsed){
36214 var sw = this.split.el.getWidth();
36216 this.split.el.setLeft(box.x);
36217 this.split.el.setTop(box.y);
36218 this.split.el.setHeight(box.height);
36221 if(this.collapsed){
36222 this.updateBody(null, box.height);
36224 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36228 Roo.bootstrap.layout.West = function(config){
36229 config.region = "west";
36230 config.cursor = "w-resize";
36232 Roo.bootstrap.layout.Split.call(this, config);
36234 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36235 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36236 this.split.el.addClass("roo-layout-split-h");
36240 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36241 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36243 onRender: function(ctr, pos)
36245 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36246 var size = this.config.initialSize || this.config.width;
36247 if(typeof size != "undefined"){
36248 this.el.setWidth(size);
36252 getBox : function(){
36253 if(this.collapsed){
36254 return this.collapsedEl.getBox();
36256 var box = this.el.getBox();
36258 box.width += this.split.el.getWidth();
36263 updateBox : function(box){
36264 if(this.split && !this.collapsed){
36265 var sw = this.split.el.getWidth();
36267 this.split.el.setLeft(box.x+box.width);
36268 this.split.el.setTop(box.y);
36269 this.split.el.setHeight(box.height);
36271 if(this.collapsed){
36272 this.updateBody(null, box.height);
36274 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36277 Roo.namespace("Roo.bootstrap.panel");/*
36279 * Ext JS Library 1.1.1
36280 * Copyright(c) 2006-2007, Ext JS, LLC.
36282 * Originally Released Under LGPL - original licence link has changed is not relivant.
36285 * <script type="text/javascript">
36288 * @class Roo.ContentPanel
36289 * @extends Roo.util.Observable
36290 * A basic ContentPanel element.
36291 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36292 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36293 * @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
36294 * @cfg {Boolean} closable True if the panel can be closed/removed
36295 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36296 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36297 * @cfg {Toolbar} toolbar A toolbar for this panel
36298 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36299 * @cfg {String} title The title for this panel
36300 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36301 * @cfg {String} url Calls {@link #setUrl} with this value
36302 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36303 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36304 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36305 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36306 * @cfg {Boolean} badges render the badges
36309 * Create a new ContentPanel.
36310 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36311 * @param {String/Object} config A string to set only the title or a config object
36312 * @param {String} content (optional) Set the HTML content for this panel
36313 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36315 Roo.bootstrap.panel.Content = function( config){
36317 this.tpl = config.tpl || false;
36319 var el = config.el;
36320 var content = config.content;
36322 if(config.autoCreate){ // xtype is available if this is called from factory
36325 this.el = Roo.get(el);
36326 if(!this.el && config && config.autoCreate){
36327 if(typeof config.autoCreate == "object"){
36328 if(!config.autoCreate.id){
36329 config.autoCreate.id = config.id||el;
36331 this.el = Roo.DomHelper.append(document.body,
36332 config.autoCreate, true);
36334 var elcfg = { tag: "div",
36335 cls: "roo-layout-inactive-content",
36339 elcfg.html = config.html;
36343 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36346 this.closable = false;
36347 this.loaded = false;
36348 this.active = false;
36351 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36353 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36355 this.wrapEl = this.el; //this.el.wrap();
36357 if (config.toolbar.items) {
36358 ti = config.toolbar.items ;
36359 delete config.toolbar.items ;
36363 this.toolbar.render(this.wrapEl, 'before');
36364 for(var i =0;i < ti.length;i++) {
36365 // Roo.log(['add child', items[i]]);
36366 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36368 this.toolbar.items = nitems;
36369 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36370 delete config.toolbar;
36374 // xtype created footer. - not sure if will work as we normally have to render first..
36375 if (this.footer && !this.footer.el && this.footer.xtype) {
36376 if (!this.wrapEl) {
36377 this.wrapEl = this.el.wrap();
36380 this.footer.container = this.wrapEl.createChild();
36382 this.footer = Roo.factory(this.footer, Roo);
36387 if(typeof config == "string"){
36388 this.title = config;
36390 Roo.apply(this, config);
36394 this.resizeEl = Roo.get(this.resizeEl, true);
36396 this.resizeEl = this.el;
36398 // handle view.xtype
36406 * Fires when this panel is activated.
36407 * @param {Roo.ContentPanel} this
36411 * @event deactivate
36412 * Fires when this panel is activated.
36413 * @param {Roo.ContentPanel} this
36415 "deactivate" : true,
36419 * Fires when this panel is resized if fitToFrame is true.
36420 * @param {Roo.ContentPanel} this
36421 * @param {Number} width The width after any component adjustments
36422 * @param {Number} height The height after any component adjustments
36428 * Fires when this tab is created
36429 * @param {Roo.ContentPanel} this
36440 if(this.autoScroll){
36441 this.resizeEl.setStyle("overflow", "auto");
36443 // fix randome scrolling
36444 //this.el.on('scroll', function() {
36445 // Roo.log('fix random scolling');
36446 // this.scrollTo('top',0);
36449 content = content || this.content;
36451 this.setContent(content);
36453 if(config && config.url){
36454 this.setUrl(this.url, this.params, this.loadOnce);
36459 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36461 if (this.view && typeof(this.view.xtype) != 'undefined') {
36462 this.view.el = this.el.appendChild(document.createElement("div"));
36463 this.view = Roo.factory(this.view);
36464 this.view.render && this.view.render(false, '');
36468 this.fireEvent('render', this);
36471 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36475 setRegion : function(region){
36476 this.region = region;
36477 this.setActiveClass(region && !this.background);
36481 setActiveClass: function(state)
36484 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36485 this.el.setStyle('position','relative');
36487 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36488 this.el.setStyle('position', 'absolute');
36493 * Returns the toolbar for this Panel if one was configured.
36494 * @return {Roo.Toolbar}
36496 getToolbar : function(){
36497 return this.toolbar;
36500 setActiveState : function(active)
36502 this.active = active;
36503 this.setActiveClass(active);
36505 if(this.fireEvent("deactivate", this) === false){
36510 this.fireEvent("activate", this);
36514 * Updates this panel's element
36515 * @param {String} content The new content
36516 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36518 setContent : function(content, loadScripts){
36519 this.el.update(content, loadScripts);
36522 ignoreResize : function(w, h){
36523 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36526 this.lastSize = {width: w, height: h};
36531 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36532 * @return {Roo.UpdateManager} The UpdateManager
36534 getUpdateManager : function(){
36535 return this.el.getUpdateManager();
36538 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36539 * @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:
36542 url: "your-url.php",
36543 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36544 callback: yourFunction,
36545 scope: yourObject, //(optional scope)
36548 text: "Loading...",
36553 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36554 * 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.
36555 * @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}
36556 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36557 * @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.
36558 * @return {Roo.ContentPanel} this
36561 var um = this.el.getUpdateManager();
36562 um.update.apply(um, arguments);
36568 * 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.
36569 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36570 * @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)
36571 * @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)
36572 * @return {Roo.UpdateManager} The UpdateManager
36574 setUrl : function(url, params, loadOnce){
36575 if(this.refreshDelegate){
36576 this.removeListener("activate", this.refreshDelegate);
36578 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36579 this.on("activate", this.refreshDelegate);
36580 return this.el.getUpdateManager();
36583 _handleRefresh : function(url, params, loadOnce){
36584 if(!loadOnce || !this.loaded){
36585 var updater = this.el.getUpdateManager();
36586 updater.update(url, params, this._setLoaded.createDelegate(this));
36590 _setLoaded : function(){
36591 this.loaded = true;
36595 * Returns this panel's id
36598 getId : function(){
36603 * Returns this panel's element - used by regiosn to add.
36604 * @return {Roo.Element}
36606 getEl : function(){
36607 return this.wrapEl || this.el;
36612 adjustForComponents : function(width, height)
36614 //Roo.log('adjustForComponents ');
36615 if(this.resizeEl != this.el){
36616 width -= this.el.getFrameWidth('lr');
36617 height -= this.el.getFrameWidth('tb');
36620 var te = this.toolbar.getEl();
36621 te.setWidth(width);
36622 height -= te.getHeight();
36625 var te = this.footer.getEl();
36626 te.setWidth(width);
36627 height -= te.getHeight();
36631 if(this.adjustments){
36632 width += this.adjustments[0];
36633 height += this.adjustments[1];
36635 return {"width": width, "height": height};
36638 setSize : function(width, height){
36639 if(this.fitToFrame && !this.ignoreResize(width, height)){
36640 if(this.fitContainer && this.resizeEl != this.el){
36641 this.el.setSize(width, height);
36643 var size = this.adjustForComponents(width, height);
36644 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36645 this.fireEvent('resize', this, size.width, size.height);
36650 * Returns this panel's title
36653 getTitle : function(){
36655 if (typeof(this.title) != 'object') {
36660 for (var k in this.title) {
36661 if (!this.title.hasOwnProperty(k)) {
36665 if (k.indexOf('-') >= 0) {
36666 var s = k.split('-');
36667 for (var i = 0; i<s.length; i++) {
36668 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36671 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36678 * Set this panel's title
36679 * @param {String} title
36681 setTitle : function(title){
36682 this.title = title;
36684 this.region.updatePanelTitle(this, title);
36689 * Returns true is this panel was configured to be closable
36690 * @return {Boolean}
36692 isClosable : function(){
36693 return this.closable;
36696 beforeSlide : function(){
36698 this.resizeEl.clip();
36701 afterSlide : function(){
36703 this.resizeEl.unclip();
36707 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36708 * Will fail silently if the {@link #setUrl} method has not been called.
36709 * This does not activate the panel, just updates its content.
36711 refresh : function(){
36712 if(this.refreshDelegate){
36713 this.loaded = false;
36714 this.refreshDelegate();
36719 * Destroys this panel
36721 destroy : function(){
36722 this.el.removeAllListeners();
36723 var tempEl = document.createElement("span");
36724 tempEl.appendChild(this.el.dom);
36725 tempEl.innerHTML = "";
36731 * form - if the content panel contains a form - this is a reference to it.
36732 * @type {Roo.form.Form}
36736 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36737 * This contains a reference to it.
36743 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36753 * @param {Object} cfg Xtype definition of item to add.
36757 getChildContainer: function () {
36758 return this.getEl();
36763 var ret = new Roo.factory(cfg);
36768 if (cfg.xtype.match(/^Form$/)) {
36771 //if (this.footer) {
36772 // el = this.footer.container.insertSibling(false, 'before');
36774 el = this.el.createChild();
36777 this.form = new Roo.form.Form(cfg);
36780 if ( this.form.allItems.length) {
36781 this.form.render(el.dom);
36785 // should only have one of theses..
36786 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36787 // views.. should not be just added - used named prop 'view''
36789 cfg.el = this.el.appendChild(document.createElement("div"));
36792 var ret = new Roo.factory(cfg);
36794 ret.render && ret.render(false, ''); // render blank..
36804 * @class Roo.bootstrap.panel.Grid
36805 * @extends Roo.bootstrap.panel.Content
36807 * Create a new GridPanel.
36808 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36809 * @param {Object} config A the config object
36815 Roo.bootstrap.panel.Grid = function(config)
36819 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36820 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36822 config.el = this.wrapper;
36823 //this.el = this.wrapper;
36825 if (config.container) {
36826 // ctor'ed from a Border/panel.grid
36829 this.wrapper.setStyle("overflow", "hidden");
36830 this.wrapper.addClass('roo-grid-container');
36835 if(config.toolbar){
36836 var tool_el = this.wrapper.createChild();
36837 this.toolbar = Roo.factory(config.toolbar);
36839 if (config.toolbar.items) {
36840 ti = config.toolbar.items ;
36841 delete config.toolbar.items ;
36845 this.toolbar.render(tool_el);
36846 for(var i =0;i < ti.length;i++) {
36847 // Roo.log(['add child', items[i]]);
36848 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36850 this.toolbar.items = nitems;
36852 delete config.toolbar;
36855 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36856 config.grid.scrollBody = true;;
36857 config.grid.monitorWindowResize = false; // turn off autosizing
36858 config.grid.autoHeight = false;
36859 config.grid.autoWidth = false;
36861 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36863 if (config.background) {
36864 // render grid on panel activation (if panel background)
36865 this.on('activate', function(gp) {
36866 if (!gp.grid.rendered) {
36867 gp.grid.render(this.wrapper);
36868 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36873 this.grid.render(this.wrapper);
36874 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36877 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36878 // ??? needed ??? config.el = this.wrapper;
36883 // xtype created footer. - not sure if will work as we normally have to render first..
36884 if (this.footer && !this.footer.el && this.footer.xtype) {
36886 var ctr = this.grid.getView().getFooterPanel(true);
36887 this.footer.dataSource = this.grid.dataSource;
36888 this.footer = Roo.factory(this.footer, Roo);
36889 this.footer.render(ctr);
36899 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36900 getId : function(){
36901 return this.grid.id;
36905 * Returns the grid for this panel
36906 * @return {Roo.bootstrap.Table}
36908 getGrid : function(){
36912 setSize : function(width, height){
36913 if(!this.ignoreResize(width, height)){
36914 var grid = this.grid;
36915 var size = this.adjustForComponents(width, height);
36916 var gridel = grid.getGridEl();
36917 gridel.setSize(size.width, size.height);
36919 var thd = grid.getGridEl().select('thead',true).first();
36920 var tbd = grid.getGridEl().select('tbody', true).first();
36922 tbd.setSize(width, height - thd.getHeight());
36931 beforeSlide : function(){
36932 this.grid.getView().scroller.clip();
36935 afterSlide : function(){
36936 this.grid.getView().scroller.unclip();
36939 destroy : function(){
36940 this.grid.destroy();
36942 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36947 * @class Roo.bootstrap.panel.Nest
36948 * @extends Roo.bootstrap.panel.Content
36950 * Create a new Panel, that can contain a layout.Border.
36953 * @param {Roo.BorderLayout} layout The layout for this panel
36954 * @param {String/Object} config A string to set only the title or a config object
36956 Roo.bootstrap.panel.Nest = function(config)
36958 // construct with only one argument..
36959 /* FIXME - implement nicer consturctors
36960 if (layout.layout) {
36962 layout = config.layout;
36963 delete config.layout;
36965 if (layout.xtype && !layout.getEl) {
36966 // then layout needs constructing..
36967 layout = Roo.factory(layout, Roo);
36971 config.el = config.layout.getEl();
36973 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36975 config.layout.monitorWindowResize = false; // turn off autosizing
36976 this.layout = config.layout;
36977 this.layout.getEl().addClass("roo-layout-nested-layout");
36984 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36986 setSize : function(width, height){
36987 if(!this.ignoreResize(width, height)){
36988 var size = this.adjustForComponents(width, height);
36989 var el = this.layout.getEl();
36990 if (size.height < 1) {
36991 el.setWidth(size.width);
36993 el.setSize(size.width, size.height);
36995 var touch = el.dom.offsetWidth;
36996 this.layout.layout();
36997 // ie requires a double layout on the first pass
36998 if(Roo.isIE && !this.initialized){
36999 this.initialized = true;
37000 this.layout.layout();
37005 // activate all subpanels if not currently active..
37007 setActiveState : function(active){
37008 this.active = active;
37009 this.setActiveClass(active);
37012 this.fireEvent("deactivate", this);
37016 this.fireEvent("activate", this);
37017 // not sure if this should happen before or after..
37018 if (!this.layout) {
37019 return; // should not happen..
37022 for (var r in this.layout.regions) {
37023 reg = this.layout.getRegion(r);
37024 if (reg.getActivePanel()) {
37025 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37026 reg.setActivePanel(reg.getActivePanel());
37029 if (!reg.panels.length) {
37032 reg.showPanel(reg.getPanel(0));
37041 * Returns the nested BorderLayout for this panel
37042 * @return {Roo.BorderLayout}
37044 getLayout : function(){
37045 return this.layout;
37049 * Adds a xtype elements to the layout of the nested panel
37053 xtype : 'ContentPanel',
37060 xtype : 'NestedLayoutPanel',
37066 items : [ ... list of content panels or nested layout panels.. ]
37070 * @param {Object} cfg Xtype definition of item to add.
37072 addxtype : function(cfg) {
37073 return this.layout.addxtype(cfg);
37078 * Ext JS Library 1.1.1
37079 * Copyright(c) 2006-2007, Ext JS, LLC.
37081 * Originally Released Under LGPL - original licence link has changed is not relivant.
37084 * <script type="text/javascript">
37087 * @class Roo.TabPanel
37088 * @extends Roo.util.Observable
37089 * A lightweight tab container.
37093 // basic tabs 1, built from existing content
37094 var tabs = new Roo.TabPanel("tabs1");
37095 tabs.addTab("script", "View Script");
37096 tabs.addTab("markup", "View Markup");
37097 tabs.activate("script");
37099 // more advanced tabs, built from javascript
37100 var jtabs = new Roo.TabPanel("jtabs");
37101 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37103 // set up the UpdateManager
37104 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37105 var updater = tab2.getUpdateManager();
37106 updater.setDefaultUrl("ajax1.htm");
37107 tab2.on('activate', updater.refresh, updater, true);
37109 // Use setUrl for Ajax loading
37110 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37111 tab3.setUrl("ajax2.htm", null, true);
37114 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37117 jtabs.activate("jtabs-1");
37120 * Create a new TabPanel.
37121 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37122 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37124 Roo.bootstrap.panel.Tabs = function(config){
37126 * The container element for this TabPanel.
37127 * @type Roo.Element
37129 this.el = Roo.get(config.el);
37132 if(typeof config == "boolean"){
37133 this.tabPosition = config ? "bottom" : "top";
37135 Roo.apply(this, config);
37139 if(this.tabPosition == "bottom"){
37140 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37141 this.el.addClass("roo-tabs-bottom");
37143 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37144 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37145 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37147 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37149 if(this.tabPosition != "bottom"){
37150 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37151 * @type Roo.Element
37153 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37154 this.el.addClass("roo-tabs-top");
37158 this.bodyEl.setStyle("position", "relative");
37160 this.active = null;
37161 this.activateDelegate = this.activate.createDelegate(this);
37166 * Fires when the active tab changes
37167 * @param {Roo.TabPanel} this
37168 * @param {Roo.TabPanelItem} activePanel The new active tab
37172 * @event beforetabchange
37173 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37174 * @param {Roo.TabPanel} this
37175 * @param {Object} e Set cancel to true on this object to cancel the tab change
37176 * @param {Roo.TabPanelItem} tab The tab being changed to
37178 "beforetabchange" : true
37181 Roo.EventManager.onWindowResize(this.onResize, this);
37182 this.cpad = this.el.getPadding("lr");
37183 this.hiddenCount = 0;
37186 // toolbar on the tabbar support...
37187 if (this.toolbar) {
37188 alert("no toolbar support yet");
37189 this.toolbar = false;
37191 var tcfg = this.toolbar;
37192 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37193 this.toolbar = new Roo.Toolbar(tcfg);
37194 if (Roo.isSafari) {
37195 var tbl = tcfg.container.child('table', true);
37196 tbl.setAttribute('width', '100%');
37204 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37207 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37209 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37211 tabPosition : "top",
37213 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37215 currentTabWidth : 0,
37217 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37221 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37225 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37227 preferredTabWidth : 175,
37229 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37231 resizeTabs : false,
37233 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37235 monitorResize : true,
37237 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37242 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37243 * @param {String} id The id of the div to use <b>or create</b>
37244 * @param {String} text The text for the tab
37245 * @param {String} content (optional) Content to put in the TabPanelItem body
37246 * @param {Boolean} closable (optional) True to create a close icon on the tab
37247 * @return {Roo.TabPanelItem} The created TabPanelItem
37249 addTab : function(id, text, content, closable, tpl)
37251 var item = new Roo.bootstrap.panel.TabItem({
37255 closable : closable,
37258 this.addTabItem(item);
37260 item.setContent(content);
37266 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37267 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37268 * @return {Roo.TabPanelItem}
37270 getTab : function(id){
37271 return this.items[id];
37275 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37276 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37278 hideTab : function(id){
37279 var t = this.items[id];
37282 this.hiddenCount++;
37283 this.autoSizeTabs();
37288 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37289 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37291 unhideTab : function(id){
37292 var t = this.items[id];
37294 t.setHidden(false);
37295 this.hiddenCount--;
37296 this.autoSizeTabs();
37301 * Adds an existing {@link Roo.TabPanelItem}.
37302 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37304 addTabItem : function(item){
37305 this.items[item.id] = item;
37306 this.items.push(item);
37307 // if(this.resizeTabs){
37308 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37309 // this.autoSizeTabs();
37311 // item.autoSize();
37316 * Removes a {@link Roo.TabPanelItem}.
37317 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37319 removeTab : function(id){
37320 var items = this.items;
37321 var tab = items[id];
37322 if(!tab) { return; }
37323 var index = items.indexOf(tab);
37324 if(this.active == tab && items.length > 1){
37325 var newTab = this.getNextAvailable(index);
37330 this.stripEl.dom.removeChild(tab.pnode.dom);
37331 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37332 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37334 items.splice(index, 1);
37335 delete this.items[tab.id];
37336 tab.fireEvent("close", tab);
37337 tab.purgeListeners();
37338 this.autoSizeTabs();
37341 getNextAvailable : function(start){
37342 var items = this.items;
37344 // look for a next tab that will slide over to
37345 // replace the one being removed
37346 while(index < items.length){
37347 var item = items[++index];
37348 if(item && !item.isHidden()){
37352 // if one isn't found select the previous tab (on the left)
37355 var item = items[--index];
37356 if(item && !item.isHidden()){
37364 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37365 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37367 disableTab : function(id){
37368 var tab = this.items[id];
37369 if(tab && this.active != tab){
37375 * Enables a {@link Roo.TabPanelItem} that is disabled.
37376 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37378 enableTab : function(id){
37379 var tab = this.items[id];
37384 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37385 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37386 * @return {Roo.TabPanelItem} The TabPanelItem.
37388 activate : function(id){
37389 var tab = this.items[id];
37393 if(tab == this.active || tab.disabled){
37397 this.fireEvent("beforetabchange", this, e, tab);
37398 if(e.cancel !== true && !tab.disabled){
37400 this.active.hide();
37402 this.active = this.items[id];
37403 this.active.show();
37404 this.fireEvent("tabchange", this, this.active);
37410 * Gets the active {@link Roo.TabPanelItem}.
37411 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37413 getActiveTab : function(){
37414 return this.active;
37418 * Updates the tab body element to fit the height of the container element
37419 * for overflow scrolling
37420 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37422 syncHeight : function(targetHeight){
37423 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37424 var bm = this.bodyEl.getMargins();
37425 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37426 this.bodyEl.setHeight(newHeight);
37430 onResize : function(){
37431 if(this.monitorResize){
37432 this.autoSizeTabs();
37437 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37439 beginUpdate : function(){
37440 this.updating = true;
37444 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37446 endUpdate : function(){
37447 this.updating = false;
37448 this.autoSizeTabs();
37452 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37454 autoSizeTabs : function(){
37455 var count = this.items.length;
37456 var vcount = count - this.hiddenCount;
37457 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37460 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37461 var availWidth = Math.floor(w / vcount);
37462 var b = this.stripBody;
37463 if(b.getWidth() > w){
37464 var tabs = this.items;
37465 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37466 if(availWidth < this.minTabWidth){
37467 /*if(!this.sleft){ // incomplete scrolling code
37468 this.createScrollButtons();
37471 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37474 if(this.currentTabWidth < this.preferredTabWidth){
37475 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37481 * Returns the number of tabs in this TabPanel.
37484 getCount : function(){
37485 return this.items.length;
37489 * Resizes all the tabs to the passed width
37490 * @param {Number} The new width
37492 setTabWidth : function(width){
37493 this.currentTabWidth = width;
37494 for(var i = 0, len = this.items.length; i < len; i++) {
37495 if(!this.items[i].isHidden()) {
37496 this.items[i].setWidth(width);
37502 * Destroys this TabPanel
37503 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37505 destroy : function(removeEl){
37506 Roo.EventManager.removeResizeListener(this.onResize, this);
37507 for(var i = 0, len = this.items.length; i < len; i++){
37508 this.items[i].purgeListeners();
37510 if(removeEl === true){
37511 this.el.update("");
37516 createStrip : function(container)
37518 var strip = document.createElement("nav");
37519 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37520 container.appendChild(strip);
37524 createStripList : function(strip)
37526 // div wrapper for retard IE
37527 // returns the "tr" element.
37528 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37529 //'<div class="x-tabs-strip-wrap">'+
37530 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37531 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37532 return strip.firstChild; //.firstChild.firstChild.firstChild;
37534 createBody : function(container)
37536 var body = document.createElement("div");
37537 Roo.id(body, "tab-body");
37538 //Roo.fly(body).addClass("x-tabs-body");
37539 Roo.fly(body).addClass("tab-content");
37540 container.appendChild(body);
37543 createItemBody :function(bodyEl, id){
37544 var body = Roo.getDom(id);
37546 body = document.createElement("div");
37549 //Roo.fly(body).addClass("x-tabs-item-body");
37550 Roo.fly(body).addClass("tab-pane");
37551 bodyEl.insertBefore(body, bodyEl.firstChild);
37555 createStripElements : function(stripEl, text, closable, tpl)
37557 var td = document.createElement("li"); // was td..
37560 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37563 stripEl.appendChild(td);
37565 td.className = "x-tabs-closable";
37566 if(!this.closeTpl){
37567 this.closeTpl = new Roo.Template(
37568 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37569 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37570 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37573 var el = this.closeTpl.overwrite(td, {"text": text});
37574 var close = el.getElementsByTagName("div")[0];
37575 var inner = el.getElementsByTagName("em")[0];
37576 return {"el": el, "close": close, "inner": inner};
37579 // not sure what this is..
37580 // if(!this.tabTpl){
37581 //this.tabTpl = new Roo.Template(
37582 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37583 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37585 // this.tabTpl = new Roo.Template(
37586 // '<a href="#">' +
37587 // '<span unselectable="on"' +
37588 // (this.disableTooltips ? '' : ' title="{text}"') +
37589 // ' >{text}</span></a>'
37595 var template = tpl || this.tabTpl || false;
37599 template = new Roo.Template(
37601 '<span unselectable="on"' +
37602 (this.disableTooltips ? '' : ' title="{text}"') +
37603 ' >{text}</span></a>'
37607 switch (typeof(template)) {
37611 template = new Roo.Template(template);
37617 var el = template.overwrite(td, {"text": text});
37619 var inner = el.getElementsByTagName("span")[0];
37621 return {"el": el, "inner": inner};
37629 * @class Roo.TabPanelItem
37630 * @extends Roo.util.Observable
37631 * Represents an individual item (tab plus body) in a TabPanel.
37632 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37633 * @param {String} id The id of this TabPanelItem
37634 * @param {String} text The text for the tab of this TabPanelItem
37635 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37637 Roo.bootstrap.panel.TabItem = function(config){
37639 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37640 * @type Roo.TabPanel
37642 this.tabPanel = config.panel;
37644 * The id for this TabPanelItem
37647 this.id = config.id;
37649 this.disabled = false;
37651 this.text = config.text;
37653 this.loaded = false;
37654 this.closable = config.closable;
37657 * The body element for this TabPanelItem.
37658 * @type Roo.Element
37660 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37661 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37662 this.bodyEl.setStyle("display", "block");
37663 this.bodyEl.setStyle("zoom", "1");
37664 //this.hideAction();
37666 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37668 this.el = Roo.get(els.el);
37669 this.inner = Roo.get(els.inner, true);
37670 this.textEl = Roo.get(this.el.dom.firstChild, true);
37671 this.pnode = Roo.get(els.el.parentNode, true);
37672 // this.el.on("mousedown", this.onTabMouseDown, this);
37673 this.el.on("click", this.onTabClick, this);
37675 if(config.closable){
37676 var c = Roo.get(els.close, true);
37677 c.dom.title = this.closeText;
37678 c.addClassOnOver("close-over");
37679 c.on("click", this.closeClick, this);
37685 * Fires when this tab becomes the active tab.
37686 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37687 * @param {Roo.TabPanelItem} this
37691 * @event beforeclose
37692 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37693 * @param {Roo.TabPanelItem} this
37694 * @param {Object} e Set cancel to true on this object to cancel the close.
37696 "beforeclose": true,
37699 * Fires when this tab is closed.
37700 * @param {Roo.TabPanelItem} this
37704 * @event deactivate
37705 * Fires when this tab is no longer the active tab.
37706 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37707 * @param {Roo.TabPanelItem} this
37709 "deactivate" : true
37711 this.hidden = false;
37713 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37716 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37718 purgeListeners : function(){
37719 Roo.util.Observable.prototype.purgeListeners.call(this);
37720 this.el.removeAllListeners();
37723 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37726 this.pnode.addClass("active");
37729 this.tabPanel.stripWrap.repaint();
37731 this.fireEvent("activate", this.tabPanel, this);
37735 * Returns true if this tab is the active tab.
37736 * @return {Boolean}
37738 isActive : function(){
37739 return this.tabPanel.getActiveTab() == this;
37743 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37746 this.pnode.removeClass("active");
37748 this.fireEvent("deactivate", this.tabPanel, this);
37751 hideAction : function(){
37752 this.bodyEl.hide();
37753 this.bodyEl.setStyle("position", "absolute");
37754 this.bodyEl.setLeft("-20000px");
37755 this.bodyEl.setTop("-20000px");
37758 showAction : function(){
37759 this.bodyEl.setStyle("position", "relative");
37760 this.bodyEl.setTop("");
37761 this.bodyEl.setLeft("");
37762 this.bodyEl.show();
37766 * Set the tooltip for the tab.
37767 * @param {String} tooltip The tab's tooltip
37769 setTooltip : function(text){
37770 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37771 this.textEl.dom.qtip = text;
37772 this.textEl.dom.removeAttribute('title');
37774 this.textEl.dom.title = text;
37778 onTabClick : function(e){
37779 e.preventDefault();
37780 this.tabPanel.activate(this.id);
37783 onTabMouseDown : function(e){
37784 e.preventDefault();
37785 this.tabPanel.activate(this.id);
37788 getWidth : function(){
37789 return this.inner.getWidth();
37792 setWidth : function(width){
37793 var iwidth = width - this.pnode.getPadding("lr");
37794 this.inner.setWidth(iwidth);
37795 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37796 this.pnode.setWidth(width);
37800 * Show or hide the tab
37801 * @param {Boolean} hidden True to hide or false to show.
37803 setHidden : function(hidden){
37804 this.hidden = hidden;
37805 this.pnode.setStyle("display", hidden ? "none" : "");
37809 * Returns true if this tab is "hidden"
37810 * @return {Boolean}
37812 isHidden : function(){
37813 return this.hidden;
37817 * Returns the text for this tab
37820 getText : function(){
37824 autoSize : function(){
37825 //this.el.beginMeasure();
37826 this.textEl.setWidth(1);
37828 * #2804 [new] Tabs in Roojs
37829 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37831 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37832 //this.el.endMeasure();
37836 * Sets the text for the tab (Note: this also sets the tooltip text)
37837 * @param {String} text The tab's text and tooltip
37839 setText : function(text){
37841 this.textEl.update(text);
37842 this.setTooltip(text);
37843 //if(!this.tabPanel.resizeTabs){
37844 // this.autoSize();
37848 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37850 activate : function(){
37851 this.tabPanel.activate(this.id);
37855 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37857 disable : function(){
37858 if(this.tabPanel.active != this){
37859 this.disabled = true;
37860 this.pnode.addClass("disabled");
37865 * Enables this TabPanelItem if it was previously disabled.
37867 enable : function(){
37868 this.disabled = false;
37869 this.pnode.removeClass("disabled");
37873 * Sets the content for this TabPanelItem.
37874 * @param {String} content The content
37875 * @param {Boolean} loadScripts true to look for and load scripts
37877 setContent : function(content, loadScripts){
37878 this.bodyEl.update(content, loadScripts);
37882 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37883 * @return {Roo.UpdateManager} The UpdateManager
37885 getUpdateManager : function(){
37886 return this.bodyEl.getUpdateManager();
37890 * Set a URL to be used to load the content for this TabPanelItem.
37891 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37892 * @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)
37893 * @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)
37894 * @return {Roo.UpdateManager} The UpdateManager
37896 setUrl : function(url, params, loadOnce){
37897 if(this.refreshDelegate){
37898 this.un('activate', this.refreshDelegate);
37900 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37901 this.on("activate", this.refreshDelegate);
37902 return this.bodyEl.getUpdateManager();
37906 _handleRefresh : function(url, params, loadOnce){
37907 if(!loadOnce || !this.loaded){
37908 var updater = this.bodyEl.getUpdateManager();
37909 updater.update(url, params, this._setLoaded.createDelegate(this));
37914 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37915 * Will fail silently if the setUrl method has not been called.
37916 * This does not activate the panel, just updates its content.
37918 refresh : function(){
37919 if(this.refreshDelegate){
37920 this.loaded = false;
37921 this.refreshDelegate();
37926 _setLoaded : function(){
37927 this.loaded = true;
37931 closeClick : function(e){
37934 this.fireEvent("beforeclose", this, o);
37935 if(o.cancel !== true){
37936 this.tabPanel.removeTab(this.id);
37940 * The text displayed in the tooltip for the close icon.
37943 closeText : "Close this tab"
37946 * This script refer to:
37947 * Title: International Telephone Input
37948 * Author: Jack O'Connor
37949 * Code version: v12.1.12
37950 * Availability: https://github.com/jackocnr/intl-tel-input.git
37953 Roo.bootstrap.PhoneInputData = function() {
37956 "Afghanistan (افغانستان)",
37961 "Albania (Shqipëri)",
37966 "Algeria (الجزائر)",
37991 "Antigua and Barbuda",
38001 "Armenia (Հայաստան)",
38017 "Austria (Österreich)",
38022 "Azerbaijan (Azərbaycan)",
38032 "Bahrain (البحرين)",
38037 "Bangladesh (বাংলাদেশ)",
38047 "Belarus (Беларусь)",
38052 "Belgium (België)",
38082 "Bosnia and Herzegovina (Босна и Херцеговина)",
38097 "British Indian Ocean Territory",
38102 "British Virgin Islands",
38112 "Bulgaria (България)",
38122 "Burundi (Uburundi)",
38127 "Cambodia (កម្ពុជា)",
38132 "Cameroon (Cameroun)",
38141 ["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"]
38144 "Cape Verde (Kabu Verdi)",
38149 "Caribbean Netherlands",
38160 "Central African Republic (République centrafricaine)",
38180 "Christmas Island",
38186 "Cocos (Keeling) Islands",
38197 "Comoros (جزر القمر)",
38202 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38207 "Congo (Republic) (Congo-Brazzaville)",
38227 "Croatia (Hrvatska)",
38248 "Czech Republic (Česká republika)",
38253 "Denmark (Danmark)",
38268 "Dominican Republic (República Dominicana)",
38272 ["809", "829", "849"]
38290 "Equatorial Guinea (Guinea Ecuatorial)",
38310 "Falkland Islands (Islas Malvinas)",
38315 "Faroe Islands (Føroyar)",
38336 "French Guiana (Guyane française)",
38341 "French Polynesia (Polynésie française)",
38356 "Georgia (საქართველო)",
38361 "Germany (Deutschland)",
38381 "Greenland (Kalaallit Nunaat)",
38418 "Guinea-Bissau (Guiné Bissau)",
38443 "Hungary (Magyarország)",
38448 "Iceland (Ísland)",
38468 "Iraq (العراق)",
38484 "Israel (ישראל)",
38511 "Jordan (الأردن)",
38516 "Kazakhstan (Казахстан)",
38537 "Kuwait (الكويت)",
38542 "Kyrgyzstan (Кыргызстан)",
38552 "Latvia (Latvija)",
38557 "Lebanon (لبنان)",
38572 "Libya (ليبيا)",
38582 "Lithuania (Lietuva)",
38597 "Macedonia (FYROM) (Македонија)",
38602 "Madagascar (Madagasikara)",
38632 "Marshall Islands",
38642 "Mauritania (موريتانيا)",
38647 "Mauritius (Moris)",
38668 "Moldova (Republica Moldova)",
38678 "Mongolia (Монгол)",
38683 "Montenegro (Crna Gora)",
38693 "Morocco (المغرب)",
38699 "Mozambique (Moçambique)",
38704 "Myanmar (Burma) (မြန်မာ)",
38709 "Namibia (Namibië)",
38724 "Netherlands (Nederland)",
38729 "New Caledonia (Nouvelle-Calédonie)",
38764 "North Korea (조선 민주주의 인민 공화국)",
38769 "Northern Mariana Islands",
38785 "Pakistan (پاکستان)",
38795 "Palestine (فلسطين)",
38805 "Papua New Guinea",
38847 "Réunion (La Réunion)",
38853 "Romania (România)",
38869 "Saint Barthélemy",
38880 "Saint Kitts and Nevis",
38890 "Saint Martin (Saint-Martin (partie française))",
38896 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
38901 "Saint Vincent and the Grenadines",
38916 "São Tomé and Príncipe (São Tomé e Príncipe)",
38921 "Saudi Arabia (المملكة العربية السعودية)",
38926 "Senegal (Sénégal)",
38956 "Slovakia (Slovensko)",
38961 "Slovenia (Slovenija)",
38971 "Somalia (Soomaaliya)",
38981 "South Korea (대한민국)",
38986 "South Sudan (جنوب السودان)",
38996 "Sri Lanka (ශ්රී ලංකාව)",
39001 "Sudan (السودان)",
39011 "Svalbard and Jan Mayen",
39022 "Sweden (Sverige)",
39027 "Switzerland (Schweiz)",
39032 "Syria (سوريا)",
39077 "Trinidad and Tobago",
39082 "Tunisia (تونس)",
39087 "Turkey (Türkiye)",
39097 "Turks and Caicos Islands",
39107 "U.S. Virgin Islands",
39117 "Ukraine (Україна)",
39122 "United Arab Emirates (الإمارات العربية المتحدة)",
39144 "Uzbekistan (Oʻzbekiston)",
39154 "Vatican City (Città del Vaticano)",
39165 "Vietnam (Việt Nam)",
39170 "Wallis and Futuna (Wallis-et-Futuna)",
39175 "Western Sahara (الصحراء الغربية)",
39181 "Yemen (اليمن)",
39205 * This script refer to:
39206 * Title: International Telephone Input
39207 * Author: Jack O'Connor
39208 * Code version: v12.1.12
39209 * Availability: https://github.com/jackocnr/intl-tel-input.git
39213 * @class Roo.bootstrap.PhoneInput
39214 * @extends Roo.bootstrap.TriggerField
39215 * An input with International dial-code selection
39217 * @cfg {String} defaultDialCode default '+852'
39218 * @cfg {Array} preferedCountries default []
39221 * Create a new PhoneInput.
39222 * @param {Object} config Configuration options
39225 Roo.bootstrap.PhoneInput = function(config) {
39226 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39229 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39231 listWidth: undefined,
39233 selectedClass: 'active',
39235 invalidClass : "has-warning",
39237 validClass: 'has-success',
39239 allowed: '0123456789',
39242 * @cfg {String} defaultDialCode The default dial code when initializing the input
39244 defaultDialCode: '+852',
39247 * @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
39249 preferedCountries: false,
39251 getAutoCreate : function()
39253 var data = Roo.bootstrap.PhoneInputData();
39254 var align = this.labelAlign || this.parentLabelAlign();
39257 this.allCountries = [];
39258 this.dialCodeMapping = [];
39260 for (var i = 0; i < data.length; i++) {
39262 this.allCountries[i] = {
39266 priority: c[3] || 0,
39267 areaCodes: c[4] || null
39269 this.dialCodeMapping[c[2]] = {
39272 priority: c[3] || 0,
39273 areaCodes: c[4] || null
39285 cls : 'form-control tel-input',
39286 autocomplete: 'new-password'
39289 var hiddenInput = {
39292 cls: 'hidden-tel-input'
39296 hiddenInput.name = this.name;
39299 if (this.disabled) {
39300 input.disabled = true;
39303 var flag_container = {
39320 cls: this.hasFeedback ? 'has-feedback' : '',
39326 cls: 'dial-code-holder',
39333 cls: 'roo-select2-container input-group',
39340 if (this.fieldLabel.length) {
39343 tooltip: 'This field is required'
39349 cls: 'control-label',
39355 html: this.fieldLabel
39358 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39364 if(this.indicatorpos == 'right') {
39365 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39372 if(align == 'left') {
39380 if(this.labelWidth > 12){
39381 label.style = "width: " + this.labelWidth + 'px';
39383 if(this.labelWidth < 13 && this.labelmd == 0){
39384 this.labelmd = this.labelWidth;
39386 if(this.labellg > 0){
39387 label.cls += ' col-lg-' + this.labellg;
39388 input.cls += ' col-lg-' + (12 - this.labellg);
39390 if(this.labelmd > 0){
39391 label.cls += ' col-md-' + this.labelmd;
39392 container.cls += ' col-md-' + (12 - this.labelmd);
39394 if(this.labelsm > 0){
39395 label.cls += ' col-sm-' + this.labelsm;
39396 container.cls += ' col-sm-' + (12 - this.labelsm);
39398 if(this.labelxs > 0){
39399 label.cls += ' col-xs-' + this.labelxs;
39400 container.cls += ' col-xs-' + (12 - this.labelxs);
39410 var settings = this;
39412 ['xs','sm','md','lg'].map(function(size){
39413 if (settings[size]) {
39414 cfg.cls += ' col-' + size + '-' + settings[size];
39418 this.store = new Roo.data.Store({
39419 proxy : new Roo.data.MemoryProxy({}),
39420 reader : new Roo.data.JsonReader({
39431 'name' : 'dialCode',
39435 'name' : 'priority',
39439 'name' : 'areaCodes',
39446 if(!this.preferedCountries) {
39447 this.preferedCountries = [
39454 var p = this.preferedCountries.reverse();
39457 for (var i = 0; i < p.length; i++) {
39458 for (var j = 0; j < this.allCountries.length; j++) {
39459 if(this.allCountries[j].iso2 == p[i]) {
39460 var t = this.allCountries[j];
39461 this.allCountries.splice(j,1);
39462 this.allCountries.unshift(t);
39468 this.store.proxy.data = {
39470 data: this.allCountries
39476 initEvents : function()
39479 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39481 this.indicator = this.indicatorEl();
39482 this.flag = this.flagEl();
39483 this.dialCodeHolder = this.dialCodeHolderEl();
39485 this.trigger = this.el.select('div.flag-box',true).first();
39486 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39491 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39492 _this.list.setWidth(lw);
39495 this.list.on('mouseover', this.onViewOver, this);
39496 this.list.on('mousemove', this.onViewMove, this);
39497 this.inputEl().on("keyup", this.onKeyUp, this);
39499 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39501 this.view = new Roo.View(this.list, this.tpl, {
39502 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39505 this.view.on('click', this.onViewClick, this);
39506 this.setValue(this.defaultDialCode);
39509 onTriggerClick : function(e)
39511 Roo.log('trigger click');
39516 if(this.isExpanded()){
39518 this.hasFocus = false;
39520 this.store.load({});
39521 this.hasFocus = true;
39526 isExpanded : function()
39528 return this.list.isVisible();
39531 collapse : function()
39533 if(!this.isExpanded()){
39537 Roo.get(document).un('mousedown', this.collapseIf, this);
39538 Roo.get(document).un('mousewheel', this.collapseIf, this);
39539 this.fireEvent('collapse', this);
39543 expand : function()
39547 if(this.isExpanded() || !this.hasFocus){
39551 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39552 this.list.setWidth(lw);
39555 this.restrictHeight();
39557 Roo.get(document).on('mousedown', this.collapseIf, this);
39558 Roo.get(document).on('mousewheel', this.collapseIf, this);
39560 this.fireEvent('expand', this);
39563 restrictHeight : function()
39565 this.list.alignTo(this.inputEl(), this.listAlign);
39566 this.list.alignTo(this.inputEl(), this.listAlign);
39569 onViewOver : function(e, t)
39571 if(this.inKeyMode){
39574 var item = this.view.findItemFromChild(t);
39577 var index = this.view.indexOf(item);
39578 this.select(index, false);
39583 onViewClick : function(view, doFocus, el, e)
39585 var index = this.view.getSelectedIndexes()[0];
39587 var r = this.store.getAt(index);
39590 this.onSelect(r, index);
39592 if(doFocus !== false && !this.blockFocus){
39593 this.inputEl().focus();
39597 onViewMove : function(e, t)
39599 this.inKeyMode = false;
39602 select : function(index, scrollIntoView)
39604 this.selectedIndex = index;
39605 this.view.select(index);
39606 if(scrollIntoView !== false){
39607 var el = this.view.getNode(index);
39609 this.list.scrollChildIntoView(el, false);
39614 createList : function()
39616 this.list = Roo.get(document.body).createChild({
39618 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39619 style: 'display:none'
39621 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39624 collapseIf : function(e)
39626 var in_combo = e.within(this.el);
39627 var in_list = e.within(this.list);
39628 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39630 if (in_combo || in_list || is_list) {
39636 onSelect : function(record, index)
39638 if(this.fireEvent('beforeselect', this, record, index) !== false){
39640 this.setFlagClass(record.data.iso2);
39641 this.setDialCode(record.data.dialCode);
39642 this.hasFocus = false;
39644 this.fireEvent('select', this, record, index);
39648 flagEl : function()
39650 var flag = this.el.select('div.flag',true).first();
39657 dialCodeHolderEl : function()
39659 var d = this.el.select('input.dial-code-holder',true).first();
39666 setDialCode : function(v)
39668 this.dialCodeHolder.dom.value = '+'+v;
39671 setFlagClass : function(n)
39673 this.flag.dom.className = 'flag '+n;
39676 getValue : function()
39678 var v = this.inputEl().getValue();
39679 if(this.dialCodeHolder) {
39680 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39685 setValue : function(v)
39687 var d = this.getDialCode(v);
39689 //invalid dial code
39690 if(v.length == 0 || !d || d.length == 0) {
39692 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39693 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39699 this.setFlagClass(this.dialCodeMapping[d].iso2);
39700 this.setDialCode(d);
39701 this.inputEl().dom.value = v.replace('+'+d,'');
39702 this.hiddenEl().dom.value = this.getValue();
39707 getDialCode : function(v = '')
39709 if (v.length == 0) {
39710 return this.dialCodeHolder.dom.value;
39714 if (v.charAt(0) != "+") {
39717 var numericChars = "";
39718 for (var i = 1; i < v.length; i++) {
39719 var c = v.charAt(i);
39722 if (this.dialCodeMapping[numericChars]) {
39723 dialCode = v.substr(1, i);
39725 if (numericChars.length == 4) {
39735 this.setValue(this.defaultDialCode);
39739 hiddenEl : function()
39741 return this.el.select('input.hidden-tel-input',true).first();
39744 onKeyUp : function(e){
39746 var k = e.getKey();
39747 var c = e.getCharCode();
39750 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39751 this.allowed.indexOf(String.fromCharCode(c)) === -1
39756 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39759 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39763 this.setValue(this.getValue());
39768 * @class Roo.bootstrap.MoneyField
39769 * @extends Roo.bootstrap.ComboBox
39770 * Bootstrap MoneyField class
39773 * Create a new MoneyField.
39774 * @param {Object} config Configuration options
39777 Roo.bootstrap.MoneyField = function(config) {
39779 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39783 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39786 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39788 decimalSeparator : ".",
39797 getAutoCreate : function()
39799 var align = this.labelAlign || this.parentLabelAlign();
39811 cls : 'form-control roo-money-amount-input',
39812 autocomplete: 'new-password'
39816 input.name = this.name;
39819 if (this.disabled) {
39820 input.disabled = true;
39823 var clg = 12 - this.inputlg;
39824 var cmd = 12 - this.inputmd;
39825 var csm = 12 - this.inputsm;
39826 var cxs = 12 - this.inputxs;
39830 cls : 'row roo-money-field',
39834 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
39838 cls: 'roo-select2-container input-group',
39842 cls : 'form-control roo-money-currency-input',
39843 autocomplete: 'new-password'
39847 cls : 'input-group-addon',
39861 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
39865 cls: this.hasFeedback ? 'has-feedback' : '',
39876 if (this.fieldLabel.length) {
39879 tooltip: 'This field is required'
39885 cls: 'control-label',
39891 html: this.fieldLabel
39894 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39900 if(this.indicatorpos == 'right') {
39901 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39908 if(align == 'left') {
39916 if(this.labelWidth > 12){
39917 label.style = "width: " + this.labelWidth + 'px';
39919 if(this.labelWidth < 13 && this.labelmd == 0){
39920 this.labelmd = this.labelWidth;
39922 if(this.labellg > 0){
39923 label.cls += ' col-lg-' + this.labellg;
39924 input.cls += ' col-lg-' + (12 - this.labellg);
39926 if(this.labelmd > 0){
39927 label.cls += ' col-md-' + this.labelmd;
39928 container.cls += ' col-md-' + (12 - this.labelmd);
39930 if(this.labelsm > 0){
39931 label.cls += ' col-sm-' + this.labelsm;
39932 container.cls += ' col-sm-' + (12 - this.labelsm);
39934 if(this.labelxs > 0){
39935 label.cls += ' col-xs-' + this.labelxs;
39936 container.cls += ' col-xs-' + (12 - this.labelxs);
39946 var settings = this;
39948 ['xs','sm','md','lg'].map(function(size){
39949 if (settings[size]) {
39950 cfg.cls += ' col-' + size + '-' + settings[size];
39958 initEvents : function()
39960 this.initCurrencyEvent();
39962 this.initNumberEvent();
39966 initCurrencyEvent : function()
39969 throw "can not find store for combo";
39972 this.store = Roo.factory(this.store, Roo.data);
39973 this.store.parent = this;
39977 this.indicator = this.indicatorEl();
39979 this.triggerEl = this.el.select('.input-group-addon', true).first();
39981 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
39983 this.currencyEl = this.el.select('.roo-money-currency-input', true).first();
39985 this.amountEl = this.el.select('.roo-money-amount-input', true).first();
39990 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39991 _this.list.setWidth(lw);
39994 this.list.on('mouseover', this.onViewOver, this);
39995 this.list.on('mousemove', this.onViewMove, this);
39996 this.list.on('scroll', this.onViewScroll, this);
39999 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40002 this.view = new Roo.View(this.list, this.tpl, {
40003 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40006 this.view.on('click', this.onViewClick, this);
40008 this.store.on('beforeload', this.onBeforeLoad, this);
40009 this.store.on('load', this.onLoad, this);
40010 this.store.on('loadexception', this.onLoadException, this);
40012 this.keyNav = new Roo.KeyNav(this.currencyEl, {
40013 "up" : function(e){
40014 this.inKeyMode = true;
40018 "down" : function(e){
40019 if(!this.isExpanded()){
40020 this.onTriggerClick();
40022 this.inKeyMode = true;
40027 "enter" : function(e){
40030 if(this.fireEvent("specialkey", this, e)){
40031 this.onViewClick(false);
40037 "esc" : function(e){
40041 "tab" : function(e){
40044 if(this.fireEvent("specialkey", this, e)){
40045 this.onViewClick(false);
40053 doRelay : function(foo, bar, hname){
40054 if(hname == 'down' || this.scope.isExpanded()){
40055 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40065 initNumberEvent : function(e)
40067 var allowed = "0123456789";
40069 if(this.allowDecimals){
40070 allowed += this.decimalSeparator;
40073 if(this.allowNegative){
40077 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40079 var keyPress = function(e){
40081 var k = e.getKey();
40083 var c = e.getCharCode();
40086 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40087 allowed.indexOf(String.fromCharCode(c)) === -1
40093 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40097 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40102 this.amountEl.on("keypress", keyPress, this);
40108 onTriggerClick : function(e)
40115 this.loadNext = false;
40117 if(this.isExpanded()){
40122 this.hasFocus = true;
40124 if(this.triggerAction == 'all') {
40125 this.doQuery(this.allQuery, true);
40129 this.doQuery(this.getRawValue());
40132 restrictHeight : function()
40134 this.list.alignTo(this.currencyEl, this.listAlign);
40135 this.list.alignTo(this.currencyEl, this.listAlign);
40138 onViewClick : function(view, doFocus, el, e)
40140 var index = this.view.getSelectedIndexes()[0];
40142 var r = this.store.getAt(index);
40145 this.onSelect(r, index);
40149 setFromData : function(o)
40155 if (this.currencyField) {
40156 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40158 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
40161 this.lastSelectionText = currency;
40162 this.currencyValue = currency;
40164 this.setCurrency(currency);
40169 setCurrency : function(v)
40171 this.currencyValue = v;
40174 this.currencyEl.dom.value = (v === null || v === undefined ? '' : v);
40179 validate : function()
40183 var v = this.getRawValue();
40186 v = this.getValue();
40189 if(this.disabled || this.allowBlank || v.length){
40194 this.markInvalid();
40198 parseValue : function(value)
40200 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40201 return isNaN(value) ? '' : value;
40204 fixPrecision : function(value)
40206 var nan = isNaN(value);
40208 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40209 return nan ? '' : value;
40212 return parseFloat(value).toFixed(this.decimalPrecision);
40215 decimalPrecisionFcn : function(v)
40217 return Math.floor(v);
40220 setValue : function(v)
40222 v = this.fixPrecision(v);
40223 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));