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 (default|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);
3193 if (pp) { // weird bug on my firefox - for some reason this is not defined
3194 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3195 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3201 * Returns true if the message box is currently displayed
3202 * @return {Boolean} True if the message box is visible, else false
3204 isVisible : function(){
3205 return dlg && dlg.isVisible();
3209 * Hides the message box if it is displayed
3212 if(this.isVisible()){
3218 * Displays a new message box, or reinitializes an existing message box, based on the config options
3219 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3220 * The following config object properties are supported:
3222 Property Type Description
3223 ---------- --------------- ------------------------------------------------------------------------------------
3224 animEl String/Element An id or Element from which the message box should animate as it opens and
3225 closes (defaults to undefined)
3226 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3227 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3228 closable Boolean False to hide the top-right close button (defaults to true). Note that
3229 progress and wait dialogs will ignore this property and always hide the
3230 close button as they can only be closed programmatically.
3231 cls String A custom CSS class to apply to the message box element
3232 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3233 displayed (defaults to 75)
3234 fn Function A callback function to execute after closing the dialog. The arguments to the
3235 function will be btn (the name of the button that was clicked, if applicable,
3236 e.g. "ok"), and text (the value of the active text field, if applicable).
3237 Progress and wait dialogs will ignore this option since they do not respond to
3238 user actions and can only be closed programmatically, so any required function
3239 should be called by the same code after it closes the dialog.
3240 icon String A CSS class that provides a background image to be used as an icon for
3241 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3242 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3243 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3244 modal Boolean False to allow user interaction with the page while the message box is
3245 displayed (defaults to true)
3246 msg String A string that will replace the existing message box body text (defaults
3247 to the XHTML-compliant non-breaking space character ' ')
3248 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3249 progress Boolean True to display a progress bar (defaults to false)
3250 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3251 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3252 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3253 title String The title text
3254 value String The string value to set into the active textbox element if displayed
3255 wait Boolean True to display a progress bar (defaults to false)
3256 width Number The width of the dialog in pixels
3263 msg: 'Please enter your address:',
3265 buttons: Roo.MessageBox.OKCANCEL,
3268 animEl: 'addAddressBtn'
3271 * @param {Object} config Configuration options
3272 * @return {Roo.MessageBox} This message box
3274 show : function(options)
3277 // this causes nightmares if you show one dialog after another
3278 // especially on callbacks..
3280 if(this.isVisible()){
3283 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3284 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3285 Roo.log("New Dialog Message:" + options.msg )
3286 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3287 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3290 var d = this.getDialog();
3292 d.setTitle(opt.title || " ");
3293 d.closeEl.setDisplayed(opt.closable !== false);
3294 activeTextEl = textboxEl;
3295 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3300 textareaEl.setHeight(typeof opt.multiline == "number" ?
3301 opt.multiline : this.defaultTextHeight);
3302 activeTextEl = textareaEl;
3311 progressEl.setDisplayed(opt.progress === true);
3312 this.updateProgress(0);
3313 activeTextEl.dom.value = opt.value || "";
3315 dlg.setDefaultButton(activeTextEl);
3317 var bs = opt.buttons;
3321 }else if(bs && bs.yes){
3322 db = buttons["yes"];
3324 dlg.setDefaultButton(db);
3326 bwidth = updateButtons(opt.buttons);
3327 this.updateText(opt.msg);
3329 d.el.addClass(opt.cls);
3331 d.proxyDrag = opt.proxyDrag === true;
3332 d.modal = opt.modal !== false;
3333 d.mask = opt.modal !== false ? mask : false;
3335 // force it to the end of the z-index stack so it gets a cursor in FF
3336 document.body.appendChild(dlg.el.dom);
3337 d.animateTarget = null;
3338 d.show(options.animEl);
3344 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3345 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3346 * and closing the message box when the process is complete.
3347 * @param {String} title The title bar text
3348 * @param {String} msg The message box body text
3349 * @return {Roo.MessageBox} This message box
3351 progress : function(title, msg){
3358 minWidth: this.minProgressWidth,
3365 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3366 * If a callback function is passed it will be called after the user clicks the button, and the
3367 * id of the button that was clicked will be passed as the only parameter to the callback
3368 * (could also be the top-right close button).
3369 * @param {String} title The title bar text
3370 * @param {String} msg The message box body text
3371 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3372 * @param {Object} scope (optional) The scope of the callback function
3373 * @return {Roo.MessageBox} This message box
3375 alert : function(title, msg, fn, scope)
3390 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3391 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3392 * You are responsible for closing the message box when the process is complete.
3393 * @param {String} msg The message box body text
3394 * @param {String} title (optional) The title bar text
3395 * @return {Roo.MessageBox} This message box
3397 wait : function(msg, title){
3408 waitTimer = Roo.TaskMgr.start({
3410 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3418 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3419 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3420 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3421 * @param {String} title The title bar text
3422 * @param {String} msg The message box body text
3423 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3424 * @param {Object} scope (optional) The scope of the callback function
3425 * @return {Roo.MessageBox} This message box
3427 confirm : function(title, msg, fn, scope){
3431 buttons: this.YESNO,
3440 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3441 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3442 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3443 * (could also be the top-right close button) and the text that was entered will be passed as the two
3444 * parameters to the callback.
3445 * @param {String} title The title bar text
3446 * @param {String} msg The message box body text
3447 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3448 * @param {Object} scope (optional) The scope of the callback function
3449 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3450 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3451 * @return {Roo.MessageBox} This message box
3453 prompt : function(title, msg, fn, scope, multiline){
3457 buttons: this.OKCANCEL,
3462 multiline: multiline,
3469 * Button config that displays a single OK button
3474 * Button config that displays Yes and No buttons
3477 YESNO : {yes:true, no:true},
3479 * Button config that displays OK and Cancel buttons
3482 OKCANCEL : {ok:true, cancel:true},
3484 * Button config that displays Yes, No and Cancel buttons
3487 YESNOCANCEL : {yes:true, no:true, cancel:true},
3490 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3493 defaultTextHeight : 75,
3495 * The maximum width in pixels of the message box (defaults to 600)
3500 * The minimum width in pixels of the message box (defaults to 100)
3505 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3506 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3509 minProgressWidth : 250,
3511 * An object containing the default button text strings that can be overriden for localized language support.
3512 * Supported properties are: ok, cancel, yes and no.
3513 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3526 * Shorthand for {@link Roo.MessageBox}
3528 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3529 Roo.Msg = Roo.Msg || Roo.MessageBox;
3538 * @class Roo.bootstrap.Navbar
3539 * @extends Roo.bootstrap.Component
3540 * Bootstrap Navbar class
3543 * Create a new Navbar
3544 * @param {Object} config The config object
3548 Roo.bootstrap.Navbar = function(config){
3549 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3553 * @event beforetoggle
3554 * Fire before toggle the menu
3555 * @param {Roo.EventObject} e
3557 "beforetoggle" : true
3561 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3570 getAutoCreate : function(){
3573 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3577 initEvents :function ()
3579 //Roo.log(this.el.select('.navbar-toggle',true));
3580 this.el.select('.navbar-toggle',true).on('click', function() {
3581 if(this.fireEvent('beforetoggle', this) !== false){
3582 this.el.select('.navbar-collapse',true).toggleClass('in');
3592 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3594 var size = this.el.getSize();
3595 this.maskEl.setSize(size.width, size.height);
3596 this.maskEl.enableDisplayMode("block");
3605 getChildContainer : function()
3607 if (this.el.select('.collapse').getCount()) {
3608 return this.el.select('.collapse',true).first();
3641 * @class Roo.bootstrap.NavSimplebar
3642 * @extends Roo.bootstrap.Navbar
3643 * Bootstrap Sidebar class
3645 * @cfg {Boolean} inverse is inverted color
3647 * @cfg {String} type (nav | pills | tabs)
3648 * @cfg {Boolean} arrangement stacked | justified
3649 * @cfg {String} align (left | right) alignment
3651 * @cfg {Boolean} main (true|false) main nav bar? default false
3652 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3654 * @cfg {String} tag (header|footer|nav|div) default is nav
3660 * Create a new Sidebar
3661 * @param {Object} config The config object
3665 Roo.bootstrap.NavSimplebar = function(config){
3666 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3669 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3685 getAutoCreate : function(){
3689 tag : this.tag || 'div',
3702 this.type = this.type || 'nav';
3703 if (['tabs','pills'].indexOf(this.type)!==-1) {
3704 cfg.cn[0].cls += ' nav-' + this.type
3708 if (this.type!=='nav') {
3709 Roo.log('nav type must be nav/tabs/pills')
3711 cfg.cn[0].cls += ' navbar-nav'
3717 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3718 cfg.cn[0].cls += ' nav-' + this.arrangement;
3722 if (this.align === 'right') {
3723 cfg.cn[0].cls += ' navbar-right';
3727 cfg.cls += ' navbar-inverse';
3754 * @class Roo.bootstrap.NavHeaderbar
3755 * @extends Roo.bootstrap.NavSimplebar
3756 * Bootstrap Sidebar class
3758 * @cfg {String} brand what is brand
3759 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3760 * @cfg {String} brand_href href of the brand
3761 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3762 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3763 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3764 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3767 * Create a new Sidebar
3768 * @param {Object} config The config object
3772 Roo.bootstrap.NavHeaderbar = function(config){
3773 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3777 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3784 desktopCenter : false,
3787 getAutoCreate : function(){
3790 tag: this.nav || 'nav',
3797 if (this.desktopCenter) {
3798 cn.push({cls : 'container', cn : []});
3805 cls: 'navbar-header',
3810 cls: 'navbar-toggle',
3811 'data-toggle': 'collapse',
3816 html: 'Toggle navigation'
3838 cls: 'collapse navbar-collapse',
3842 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3844 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3845 cfg.cls += ' navbar-' + this.position;
3847 // tag can override this..
3849 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3852 if (this.brand !== '') {
3855 href: this.brand_href ? this.brand_href : '#',
3856 cls: 'navbar-brand',
3864 cfg.cls += ' main-nav';
3872 getHeaderChildContainer : function()
3874 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3875 return this.el.select('.navbar-header',true).first();
3878 return this.getChildContainer();
3882 initEvents : function()
3884 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3886 if (this.autohide) {
3891 Roo.get(document).on('scroll',function(e) {
3892 var ns = Roo.get(document).getScroll().top;
3893 var os = prevScroll;
3897 ft.removeClass('slideDown');
3898 ft.addClass('slideUp');
3901 ft.removeClass('slideUp');
3902 ft.addClass('slideDown');
3923 * @class Roo.bootstrap.NavSidebar
3924 * @extends Roo.bootstrap.Navbar
3925 * Bootstrap Sidebar class
3928 * Create a new Sidebar
3929 * @param {Object} config The config object
3933 Roo.bootstrap.NavSidebar = function(config){
3934 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3937 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3939 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3941 getAutoCreate : function(){
3946 cls: 'sidebar sidebar-nav'
3968 * @class Roo.bootstrap.NavGroup
3969 * @extends Roo.bootstrap.Component
3970 * Bootstrap NavGroup class
3971 * @cfg {String} align (left|right)
3972 * @cfg {Boolean} inverse
3973 * @cfg {String} type (nav|pills|tab) default nav
3974 * @cfg {String} navId - reference Id for navbar.
3978 * Create a new nav group
3979 * @param {Object} config The config object
3982 Roo.bootstrap.NavGroup = function(config){
3983 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3986 Roo.bootstrap.NavGroup.register(this);
3990 * Fires when the active item changes
3991 * @param {Roo.bootstrap.NavGroup} this
3992 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3993 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4000 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4011 getAutoCreate : function()
4013 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4020 if (['tabs','pills'].indexOf(this.type)!==-1) {
4021 cfg.cls += ' nav-' + this.type
4023 if (this.type!=='nav') {
4024 Roo.log('nav type must be nav/tabs/pills')
4026 cfg.cls += ' navbar-nav'
4029 if (this.parent() && this.parent().sidebar) {
4032 cls: 'dashboard-menu sidebar-menu'
4038 if (this.form === true) {
4044 if (this.align === 'right') {
4045 cfg.cls += ' navbar-right';
4047 cfg.cls += ' navbar-left';
4051 if (this.align === 'right') {
4052 cfg.cls += ' navbar-right';
4056 cfg.cls += ' navbar-inverse';
4064 * sets the active Navigation item
4065 * @param {Roo.bootstrap.NavItem} the new current navitem
4067 setActiveItem : function(item)
4070 Roo.each(this.navItems, function(v){
4075 v.setActive(false, true);
4082 item.setActive(true, true);
4083 this.fireEvent('changed', this, item, prev);
4088 * gets the active Navigation item
4089 * @return {Roo.bootstrap.NavItem} the current navitem
4091 getActive : function()
4095 Roo.each(this.navItems, function(v){
4106 indexOfNav : function()
4110 Roo.each(this.navItems, function(v,i){
4121 * adds a Navigation item
4122 * @param {Roo.bootstrap.NavItem} the navitem to add
4124 addItem : function(cfg)
4126 var cn = new Roo.bootstrap.NavItem(cfg);
4128 cn.parentId = this.id;
4129 cn.onRender(this.el, null);
4133 * register a Navigation item
4134 * @param {Roo.bootstrap.NavItem} the navitem to add
4136 register : function(item)
4138 this.navItems.push( item);
4139 item.navId = this.navId;
4144 * clear all the Navigation item
4147 clearAll : function()
4150 this.el.dom.innerHTML = '';
4153 getNavItem: function(tabId)
4156 Roo.each(this.navItems, function(e) {
4157 if (e.tabId == tabId) {
4167 setActiveNext : function()
4169 var i = this.indexOfNav(this.getActive());
4170 if (i > this.navItems.length) {
4173 this.setActiveItem(this.navItems[i+1]);
4175 setActivePrev : function()
4177 var i = this.indexOfNav(this.getActive());
4181 this.setActiveItem(this.navItems[i-1]);
4183 clearWasActive : function(except) {
4184 Roo.each(this.navItems, function(e) {
4185 if (e.tabId != except.tabId && e.was_active) {
4186 e.was_active = false;
4193 getWasActive : function ()
4196 Roo.each(this.navItems, function(e) {
4211 Roo.apply(Roo.bootstrap.NavGroup, {
4215 * register a Navigation Group
4216 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4218 register : function(navgrp)
4220 this.groups[navgrp.navId] = navgrp;
4224 * fetch a Navigation Group based on the navigation ID
4225 * @param {string} the navgroup to add
4226 * @returns {Roo.bootstrap.NavGroup} the navgroup
4228 get: function(navId) {
4229 if (typeof(this.groups[navId]) == 'undefined') {
4231 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4233 return this.groups[navId] ;
4248 * @class Roo.bootstrap.NavItem
4249 * @extends Roo.bootstrap.Component
4250 * Bootstrap Navbar.NavItem class
4251 * @cfg {String} href link to
4252 * @cfg {String} html content of button
4253 * @cfg {String} badge text inside badge
4254 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4255 * @cfg {String} glyphicon name of glyphicon
4256 * @cfg {String} icon name of font awesome icon
4257 * @cfg {Boolean} active Is item active
4258 * @cfg {Boolean} disabled Is item disabled
4260 * @cfg {Boolean} preventDefault (true | false) default false
4261 * @cfg {String} tabId the tab that this item activates.
4262 * @cfg {String} tagtype (a|span) render as a href or span?
4263 * @cfg {Boolean} animateRef (true|false) link to element default false
4266 * Create a new Navbar Item
4267 * @param {Object} config The config object
4269 Roo.bootstrap.NavItem = function(config){
4270 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4275 * The raw click event for the entire grid.
4276 * @param {Roo.EventObject} e
4281 * Fires when the active item active state changes
4282 * @param {Roo.bootstrap.NavItem} this
4283 * @param {boolean} state the new state
4289 * Fires when scroll to element
4290 * @param {Roo.bootstrap.NavItem} this
4291 * @param {Object} options
4292 * @param {Roo.EventObject} e
4300 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4308 preventDefault : false,
4315 getAutoCreate : function(){
4324 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4326 if (this.disabled) {
4327 cfg.cls += ' disabled';
4330 if (this.href || this.html || this.glyphicon || this.icon) {
4334 href : this.href || "#",
4335 html: this.html || ''
4340 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4343 if(this.glyphicon) {
4344 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4349 cfg.cn[0].html += " <span class='caret'></span>";
4353 if (this.badge !== '') {
4355 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4363 initEvents: function()
4365 if (typeof (this.menu) != 'undefined') {
4366 this.menu.parentType = this.xtype;
4367 this.menu.triggerEl = this.el;
4368 this.menu = this.addxtype(Roo.apply({}, this.menu));
4371 this.el.select('a',true).on('click', this.onClick, this);
4373 if(this.tagtype == 'span'){
4374 this.el.select('span',true).on('click', this.onClick, this);
4377 // at this point parent should be available..
4378 this.parent().register(this);
4381 onClick : function(e)
4383 if (e.getTarget('.dropdown-menu-item')) {
4384 // did you click on a menu itemm.... - then don't trigger onclick..
4389 this.preventDefault ||
4392 Roo.log("NavItem - prevent Default?");
4396 if (this.disabled) {
4400 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4401 if (tg && tg.transition) {
4402 Roo.log("waiting for the transitionend");
4408 //Roo.log("fire event clicked");
4409 if(this.fireEvent('click', this, e) === false){
4413 if(this.tagtype == 'span'){
4417 //Roo.log(this.href);
4418 var ael = this.el.select('a',true).first();
4421 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4422 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4423 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4424 return; // ignore... - it's a 'hash' to another page.
4426 Roo.log("NavItem - prevent Default?");
4428 this.scrollToElement(e);
4432 var p = this.parent();
4434 if (['tabs','pills'].indexOf(p.type)!==-1) {
4435 if (typeof(p.setActiveItem) !== 'undefined') {
4436 p.setActiveItem(this);
4440 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4441 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4442 // remove the collapsed menu expand...
4443 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4447 isActive: function () {
4450 setActive : function(state, fire, is_was_active)
4452 if (this.active && !state && this.navId) {
4453 this.was_active = true;
4454 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4456 nv.clearWasActive(this);
4460 this.active = state;
4463 this.el.removeClass('active');
4464 } else if (!this.el.hasClass('active')) {
4465 this.el.addClass('active');
4468 this.fireEvent('changed', this, state);
4471 // show a panel if it's registered and related..
4473 if (!this.navId || !this.tabId || !state || is_was_active) {
4477 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4481 var pan = tg.getPanelByName(this.tabId);
4485 // if we can not flip to new panel - go back to old nav highlight..
4486 if (false == tg.showPanel(pan)) {
4487 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4489 var onav = nv.getWasActive();
4491 onav.setActive(true, false, true);
4500 // this should not be here...
4501 setDisabled : function(state)
4503 this.disabled = state;
4505 this.el.removeClass('disabled');
4506 } else if (!this.el.hasClass('disabled')) {
4507 this.el.addClass('disabled');
4513 * Fetch the element to display the tooltip on.
4514 * @return {Roo.Element} defaults to this.el
4516 tooltipEl : function()
4518 return this.el.select('' + this.tagtype + '', true).first();
4521 scrollToElement : function(e)
4523 var c = document.body;
4526 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4528 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4529 c = document.documentElement;
4532 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4538 var o = target.calcOffsetsTo(c);
4545 this.fireEvent('scrollto', this, options, e);
4547 Roo.get(c).scrollTo('top', options.value, true);
4560 * <span> icon </span>
4561 * <span> text </span>
4562 * <span>badge </span>
4566 * @class Roo.bootstrap.NavSidebarItem
4567 * @extends Roo.bootstrap.NavItem
4568 * Bootstrap Navbar.NavSidebarItem class
4569 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4570 * {Boolean} open is the menu open
4571 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4572 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4573 * {String} buttonSize (sm|md|lg)the extra classes for the button
4574 * {Boolean} showArrow show arrow next to the text (default true)
4576 * Create a new Navbar Button
4577 * @param {Object} config The config object
4579 Roo.bootstrap.NavSidebarItem = function(config){
4580 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4585 * The raw click event for the entire grid.
4586 * @param {Roo.EventObject} e
4591 * Fires when the active item active state changes
4592 * @param {Roo.bootstrap.NavSidebarItem} this
4593 * @param {boolean} state the new state
4601 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4603 badgeWeight : 'default',
4609 buttonWeight : 'default',
4615 getAutoCreate : function(){
4620 href : this.href || '#',
4626 if(this.buttonView){
4629 href : this.href || '#',
4630 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4643 cfg.cls += ' active';
4646 if (this.disabled) {
4647 cfg.cls += ' disabled';
4650 cfg.cls += ' open x-open';
4653 if (this.glyphicon || this.icon) {
4654 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4655 a.cn.push({ tag : 'i', cls : c }) ;
4658 if(!this.buttonView){
4661 html : this.html || ''
4668 if (this.badge !== '') {
4669 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4675 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4678 a.cls += ' dropdown-toggle treeview' ;
4684 initEvents : function()
4686 if (typeof (this.menu) != 'undefined') {
4687 this.menu.parentType = this.xtype;
4688 this.menu.triggerEl = this.el;
4689 this.menu = this.addxtype(Roo.apply({}, this.menu));
4692 this.el.on('click', this.onClick, this);
4694 if(this.badge !== ''){
4695 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4700 onClick : function(e)
4707 if(this.preventDefault){
4711 this.fireEvent('click', this);
4714 disable : function()
4716 this.setDisabled(true);
4721 this.setDisabled(false);
4724 setDisabled : function(state)
4726 if(this.disabled == state){
4730 this.disabled = state;
4733 this.el.addClass('disabled');
4737 this.el.removeClass('disabled');
4742 setActive : function(state)
4744 if(this.active == state){
4748 this.active = state;
4751 this.el.addClass('active');
4755 this.el.removeClass('active');
4760 isActive: function ()
4765 setBadge : function(str)
4771 this.badgeEl.dom.innerHTML = str;
4788 * @class Roo.bootstrap.Row
4789 * @extends Roo.bootstrap.Component
4790 * Bootstrap Row class (contains columns...)
4794 * @param {Object} config The config object
4797 Roo.bootstrap.Row = function(config){
4798 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4801 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4803 getAutoCreate : function(){
4822 * @class Roo.bootstrap.Element
4823 * @extends Roo.bootstrap.Component
4824 * Bootstrap Element class
4825 * @cfg {String} html contents of the element
4826 * @cfg {String} tag tag of the element
4827 * @cfg {String} cls class of the element
4828 * @cfg {Boolean} preventDefault (true|false) default false
4829 * @cfg {Boolean} clickable (true|false) default false
4832 * Create a new Element
4833 * @param {Object} config The config object
4836 Roo.bootstrap.Element = function(config){
4837 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4843 * When a element is chick
4844 * @param {Roo.bootstrap.Element} this
4845 * @param {Roo.EventObject} e
4851 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4856 preventDefault: false,
4859 getAutoCreate : function(){
4870 initEvents: function()
4872 Roo.bootstrap.Element.superclass.initEvents.call(this);
4875 this.el.on('click', this.onClick, this);
4880 onClick : function(e)
4882 if(this.preventDefault){
4886 this.fireEvent('click', this, e);
4889 getValue : function()
4891 return this.el.dom.innerHTML;
4894 setValue : function(value)
4896 this.el.dom.innerHTML = value;
4911 * @class Roo.bootstrap.Pagination
4912 * @extends Roo.bootstrap.Component
4913 * Bootstrap Pagination class
4914 * @cfg {String} size xs | sm | md | lg
4915 * @cfg {Boolean} inverse false | true
4918 * Create a new Pagination
4919 * @param {Object} config The config object
4922 Roo.bootstrap.Pagination = function(config){
4923 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4926 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4932 getAutoCreate : function(){
4938 cfg.cls += ' inverse';
4944 cfg.cls += " " + this.cls;
4962 * @class Roo.bootstrap.PaginationItem
4963 * @extends Roo.bootstrap.Component
4964 * Bootstrap PaginationItem class
4965 * @cfg {String} html text
4966 * @cfg {String} href the link
4967 * @cfg {Boolean} preventDefault (true | false) default true
4968 * @cfg {Boolean} active (true | false) default false
4969 * @cfg {Boolean} disabled default false
4973 * Create a new PaginationItem
4974 * @param {Object} config The config object
4978 Roo.bootstrap.PaginationItem = function(config){
4979 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4984 * The raw click event for the entire grid.
4985 * @param {Roo.EventObject} e
4991 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4995 preventDefault: true,
5000 getAutoCreate : function(){
5006 href : this.href ? this.href : '#',
5007 html : this.html ? this.html : ''
5017 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5021 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5027 initEvents: function() {
5029 this.el.on('click', this.onClick, this);
5032 onClick : function(e)
5034 Roo.log('PaginationItem on click ');
5035 if(this.preventDefault){
5043 this.fireEvent('click', this, e);
5059 * @class Roo.bootstrap.Slider
5060 * @extends Roo.bootstrap.Component
5061 * Bootstrap Slider class
5064 * Create a new Slider
5065 * @param {Object} config The config object
5068 Roo.bootstrap.Slider = function(config){
5069 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5072 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5074 getAutoCreate : function(){
5078 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5082 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5094 * Ext JS Library 1.1.1
5095 * Copyright(c) 2006-2007, Ext JS, LLC.
5097 * Originally Released Under LGPL - original licence link has changed is not relivant.
5100 * <script type="text/javascript">
5105 * @class Roo.grid.ColumnModel
5106 * @extends Roo.util.Observable
5107 * This is the default implementation of a ColumnModel used by the Grid. It defines
5108 * the columns in the grid.
5111 var colModel = new Roo.grid.ColumnModel([
5112 {header: "Ticker", width: 60, sortable: true, locked: true},
5113 {header: "Company Name", width: 150, sortable: true},
5114 {header: "Market Cap.", width: 100, sortable: true},
5115 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5116 {header: "Employees", width: 100, sortable: true, resizable: false}
5121 * The config options listed for this class are options which may appear in each
5122 * individual column definition.
5123 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5125 * @param {Object} config An Array of column config objects. See this class's
5126 * config objects for details.
5128 Roo.grid.ColumnModel = function(config){
5130 * The config passed into the constructor
5132 this.config = config;
5135 // if no id, create one
5136 // if the column does not have a dataIndex mapping,
5137 // map it to the order it is in the config
5138 for(var i = 0, len = config.length; i < len; i++){
5140 if(typeof c.dataIndex == "undefined"){
5143 if(typeof c.renderer == "string"){
5144 c.renderer = Roo.util.Format[c.renderer];
5146 if(typeof c.id == "undefined"){
5149 if(c.editor && c.editor.xtype){
5150 c.editor = Roo.factory(c.editor, Roo.grid);
5152 if(c.editor && c.editor.isFormField){
5153 c.editor = new Roo.grid.GridEditor(c.editor);
5155 this.lookup[c.id] = c;
5159 * The width of columns which have no width specified (defaults to 100)
5162 this.defaultWidth = 100;
5165 * Default sortable of columns which have no sortable specified (defaults to false)
5168 this.defaultSortable = false;
5172 * @event widthchange
5173 * Fires when the width of a column changes.
5174 * @param {ColumnModel} this
5175 * @param {Number} columnIndex The column index
5176 * @param {Number} newWidth The new width
5178 "widthchange": true,
5180 * @event headerchange
5181 * Fires when the text of a header changes.
5182 * @param {ColumnModel} this
5183 * @param {Number} columnIndex The column index
5184 * @param {Number} newText The new header text
5186 "headerchange": true,
5188 * @event hiddenchange
5189 * Fires when a column is hidden or "unhidden".
5190 * @param {ColumnModel} this
5191 * @param {Number} columnIndex The column index
5192 * @param {Boolean} hidden true if hidden, false otherwise
5194 "hiddenchange": true,
5196 * @event columnmoved
5197 * Fires when a column is moved.
5198 * @param {ColumnModel} this
5199 * @param {Number} oldIndex
5200 * @param {Number} newIndex
5202 "columnmoved" : true,
5204 * @event columlockchange
5205 * Fires when a column's locked state is changed
5206 * @param {ColumnModel} this
5207 * @param {Number} colIndex
5208 * @param {Boolean} locked true if locked
5210 "columnlockchange" : true
5212 Roo.grid.ColumnModel.superclass.constructor.call(this);
5214 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5216 * @cfg {String} header The header text to display in the Grid view.
5219 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5220 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5221 * specified, the column's index is used as an index into the Record's data Array.
5224 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5225 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5228 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5229 * Defaults to the value of the {@link #defaultSortable} property.
5230 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5233 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5236 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5239 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5242 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5245 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5246 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5247 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5248 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5251 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5254 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5257 * @cfg {String} cursor (Optional)
5260 * @cfg {String} tooltip (Optional)
5263 * @cfg {Number} xs (Optional)
5266 * @cfg {Number} sm (Optional)
5269 * @cfg {Number} md (Optional)
5272 * @cfg {Number} lg (Optional)
5275 * Returns the id of the column at the specified index.
5276 * @param {Number} index The column index
5277 * @return {String} the id
5279 getColumnId : function(index){
5280 return this.config[index].id;
5284 * Returns the column for a specified id.
5285 * @param {String} id The column id
5286 * @return {Object} the column
5288 getColumnById : function(id){
5289 return this.lookup[id];
5294 * Returns the column for a specified dataIndex.
5295 * @param {String} dataIndex The column dataIndex
5296 * @return {Object|Boolean} the column or false if not found
5298 getColumnByDataIndex: function(dataIndex){
5299 var index = this.findColumnIndex(dataIndex);
5300 return index > -1 ? this.config[index] : false;
5304 * Returns the index for a specified column id.
5305 * @param {String} id The column id
5306 * @return {Number} the index, or -1 if not found
5308 getIndexById : function(id){
5309 for(var i = 0, len = this.config.length; i < len; i++){
5310 if(this.config[i].id == id){
5318 * Returns the index for a specified column dataIndex.
5319 * @param {String} dataIndex The column dataIndex
5320 * @return {Number} the index, or -1 if not found
5323 findColumnIndex : function(dataIndex){
5324 for(var i = 0, len = this.config.length; i < len; i++){
5325 if(this.config[i].dataIndex == dataIndex){
5333 moveColumn : function(oldIndex, newIndex){
5334 var c = this.config[oldIndex];
5335 this.config.splice(oldIndex, 1);
5336 this.config.splice(newIndex, 0, c);
5337 this.dataMap = null;
5338 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5341 isLocked : function(colIndex){
5342 return this.config[colIndex].locked === true;
5345 setLocked : function(colIndex, value, suppressEvent){
5346 if(this.isLocked(colIndex) == value){
5349 this.config[colIndex].locked = value;
5351 this.fireEvent("columnlockchange", this, colIndex, value);
5355 getTotalLockedWidth : function(){
5357 for(var i = 0; i < this.config.length; i++){
5358 if(this.isLocked(i) && !this.isHidden(i)){
5359 this.totalWidth += this.getColumnWidth(i);
5365 getLockedCount : function(){
5366 for(var i = 0, len = this.config.length; i < len; i++){
5367 if(!this.isLocked(i)){
5372 return this.config.length;
5376 * Returns the number of columns.
5379 getColumnCount : function(visibleOnly){
5380 if(visibleOnly === true){
5382 for(var i = 0, len = this.config.length; i < len; i++){
5383 if(!this.isHidden(i)){
5389 return this.config.length;
5393 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5394 * @param {Function} fn
5395 * @param {Object} scope (optional)
5396 * @return {Array} result
5398 getColumnsBy : function(fn, scope){
5400 for(var i = 0, len = this.config.length; i < len; i++){
5401 var c = this.config[i];
5402 if(fn.call(scope||this, c, i) === true){
5410 * Returns true if the specified column is sortable.
5411 * @param {Number} col The column index
5414 isSortable : function(col){
5415 if(typeof this.config[col].sortable == "undefined"){
5416 return this.defaultSortable;
5418 return this.config[col].sortable;
5422 * Returns the rendering (formatting) function defined for the column.
5423 * @param {Number} col The column index.
5424 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5426 getRenderer : function(col){
5427 if(!this.config[col].renderer){
5428 return Roo.grid.ColumnModel.defaultRenderer;
5430 return this.config[col].renderer;
5434 * Sets the rendering (formatting) function for a column.
5435 * @param {Number} col The column index
5436 * @param {Function} fn The function to use to process the cell's raw data
5437 * to return HTML markup for the grid view. The render function is called with
5438 * the following parameters:<ul>
5439 * <li>Data value.</li>
5440 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5441 * <li>css A CSS style string to apply to the table cell.</li>
5442 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5443 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5444 * <li>Row index</li>
5445 * <li>Column index</li>
5446 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5448 setRenderer : function(col, fn){
5449 this.config[col].renderer = fn;
5453 * Returns the width for the specified column.
5454 * @param {Number} col The column index
5457 getColumnWidth : function(col){
5458 return this.config[col].width * 1 || this.defaultWidth;
5462 * Sets the width for a column.
5463 * @param {Number} col The column index
5464 * @param {Number} width The new width
5466 setColumnWidth : function(col, width, suppressEvent){
5467 this.config[col].width = width;
5468 this.totalWidth = null;
5470 this.fireEvent("widthchange", this, col, width);
5475 * Returns the total width of all columns.
5476 * @param {Boolean} includeHidden True to include hidden column widths
5479 getTotalWidth : function(includeHidden){
5480 if(!this.totalWidth){
5481 this.totalWidth = 0;
5482 for(var i = 0, len = this.config.length; i < len; i++){
5483 if(includeHidden || !this.isHidden(i)){
5484 this.totalWidth += this.getColumnWidth(i);
5488 return this.totalWidth;
5492 * Returns the header for the specified column.
5493 * @param {Number} col The column index
5496 getColumnHeader : function(col){
5497 return this.config[col].header;
5501 * Sets the header for a column.
5502 * @param {Number} col The column index
5503 * @param {String} header The new header
5505 setColumnHeader : function(col, header){
5506 this.config[col].header = header;
5507 this.fireEvent("headerchange", this, col, header);
5511 * Returns the tooltip for the specified column.
5512 * @param {Number} col The column index
5515 getColumnTooltip : function(col){
5516 return this.config[col].tooltip;
5519 * Sets the tooltip for a column.
5520 * @param {Number} col The column index
5521 * @param {String} tooltip The new tooltip
5523 setColumnTooltip : function(col, tooltip){
5524 this.config[col].tooltip = tooltip;
5528 * Returns the dataIndex for the specified column.
5529 * @param {Number} col The column index
5532 getDataIndex : function(col){
5533 return this.config[col].dataIndex;
5537 * Sets the dataIndex for a column.
5538 * @param {Number} col The column index
5539 * @param {Number} dataIndex The new dataIndex
5541 setDataIndex : function(col, dataIndex){
5542 this.config[col].dataIndex = dataIndex;
5548 * Returns true if the cell is editable.
5549 * @param {Number} colIndex The column index
5550 * @param {Number} rowIndex The row index - this is nto actually used..?
5553 isCellEditable : function(colIndex, rowIndex){
5554 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5558 * Returns the editor defined for the cell/column.
5559 * return false or null to disable editing.
5560 * @param {Number} colIndex The column index
5561 * @param {Number} rowIndex The row index
5564 getCellEditor : function(colIndex, rowIndex){
5565 return this.config[colIndex].editor;
5569 * Sets if a column is editable.
5570 * @param {Number} col The column index
5571 * @param {Boolean} editable True if the column is editable
5573 setEditable : function(col, editable){
5574 this.config[col].editable = editable;
5579 * Returns true if the column is hidden.
5580 * @param {Number} colIndex The column index
5583 isHidden : function(colIndex){
5584 return this.config[colIndex].hidden;
5589 * Returns true if the column width cannot be changed
5591 isFixed : function(colIndex){
5592 return this.config[colIndex].fixed;
5596 * Returns true if the column can be resized
5599 isResizable : function(colIndex){
5600 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5603 * Sets if a column is hidden.
5604 * @param {Number} colIndex The column index
5605 * @param {Boolean} hidden True if the column is hidden
5607 setHidden : function(colIndex, hidden){
5608 this.config[colIndex].hidden = hidden;
5609 this.totalWidth = null;
5610 this.fireEvent("hiddenchange", this, colIndex, hidden);
5614 * Sets the editor for a column.
5615 * @param {Number} col The column index
5616 * @param {Object} editor The editor object
5618 setEditor : function(col, editor){
5619 this.config[col].editor = editor;
5623 Roo.grid.ColumnModel.defaultRenderer = function(value)
5625 if(typeof value == "object") {
5628 if(typeof value == "string" && value.length < 1){
5632 return String.format("{0}", value);
5635 // Alias for backwards compatibility
5636 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5639 * Ext JS Library 1.1.1
5640 * Copyright(c) 2006-2007, Ext JS, LLC.
5642 * Originally Released Under LGPL - original licence link has changed is not relivant.
5645 * <script type="text/javascript">
5649 * @class Roo.LoadMask
5650 * A simple utility class for generically masking elements while loading data. If the element being masked has
5651 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5652 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5653 * element's UpdateManager load indicator and will be destroyed after the initial load.
5655 * Create a new LoadMask
5656 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5657 * @param {Object} config The config object
5659 Roo.LoadMask = function(el, config){
5660 this.el = Roo.get(el);
5661 Roo.apply(this, config);
5663 this.store.on('beforeload', this.onBeforeLoad, this);
5664 this.store.on('load', this.onLoad, this);
5665 this.store.on('loadexception', this.onLoadException, this);
5666 this.removeMask = false;
5668 var um = this.el.getUpdateManager();
5669 um.showLoadIndicator = false; // disable the default indicator
5670 um.on('beforeupdate', this.onBeforeLoad, this);
5671 um.on('update', this.onLoad, this);
5672 um.on('failure', this.onLoad, this);
5673 this.removeMask = true;
5677 Roo.LoadMask.prototype = {
5679 * @cfg {Boolean} removeMask
5680 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5681 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5685 * The text to display in a centered loading message box (defaults to 'Loading...')
5689 * @cfg {String} msgCls
5690 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5692 msgCls : 'x-mask-loading',
5695 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5701 * Disables the mask to prevent it from being displayed
5703 disable : function(){
5704 this.disabled = true;
5708 * Enables the mask so that it can be displayed
5710 enable : function(){
5711 this.disabled = false;
5714 onLoadException : function()
5718 if (typeof(arguments[3]) != 'undefined') {
5719 Roo.MessageBox.alert("Error loading",arguments[3]);
5723 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5724 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5731 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5736 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5740 onBeforeLoad : function(){
5742 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5747 destroy : function(){
5749 this.store.un('beforeload', this.onBeforeLoad, this);
5750 this.store.un('load', this.onLoad, this);
5751 this.store.un('loadexception', this.onLoadException, this);
5753 var um = this.el.getUpdateManager();
5754 um.un('beforeupdate', this.onBeforeLoad, this);
5755 um.un('update', this.onLoad, this);
5756 um.un('failure', this.onLoad, this);
5767 * @class Roo.bootstrap.Table
5768 * @extends Roo.bootstrap.Component
5769 * Bootstrap Table class
5770 * @cfg {String} cls table class
5771 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5772 * @cfg {String} bgcolor Specifies the background color for a table
5773 * @cfg {Number} border Specifies whether the table cells should have borders or not
5774 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5775 * @cfg {Number} cellspacing Specifies the space between cells
5776 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5777 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5778 * @cfg {String} sortable Specifies that the table should be sortable
5779 * @cfg {String} summary Specifies a summary of the content of a table
5780 * @cfg {Number} width Specifies the width of a table
5781 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5783 * @cfg {boolean} striped Should the rows be alternative striped
5784 * @cfg {boolean} bordered Add borders to the table
5785 * @cfg {boolean} hover Add hover highlighting
5786 * @cfg {boolean} condensed Format condensed
5787 * @cfg {boolean} responsive Format condensed
5788 * @cfg {Boolean} loadMask (true|false) default false
5789 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5790 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5791 * @cfg {Boolean} rowSelection (true|false) default false
5792 * @cfg {Boolean} cellSelection (true|false) default false
5793 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5794 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5795 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5799 * Create a new Table
5800 * @param {Object} config The config object
5803 Roo.bootstrap.Table = function(config){
5804 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5809 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5810 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5811 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5812 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5814 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5816 this.sm.grid = this;
5817 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5818 this.sm = this.selModel;
5819 this.sm.xmodule = this.xmodule || false;
5822 if (this.cm && typeof(this.cm.config) == 'undefined') {
5823 this.colModel = new Roo.grid.ColumnModel(this.cm);
5824 this.cm = this.colModel;
5825 this.cm.xmodule = this.xmodule || false;
5828 this.store= Roo.factory(this.store, Roo.data);
5829 this.ds = this.store;
5830 this.ds.xmodule = this.xmodule || false;
5833 if (this.footer && this.store) {
5834 this.footer.dataSource = this.ds;
5835 this.footer = Roo.factory(this.footer);
5842 * Fires when a cell is clicked
5843 * @param {Roo.bootstrap.Table} this
5844 * @param {Roo.Element} el
5845 * @param {Number} rowIndex
5846 * @param {Number} columnIndex
5847 * @param {Roo.EventObject} e
5851 * @event celldblclick
5852 * Fires when a cell is double clicked
5853 * @param {Roo.bootstrap.Table} this
5854 * @param {Roo.Element} el
5855 * @param {Number} rowIndex
5856 * @param {Number} columnIndex
5857 * @param {Roo.EventObject} e
5859 "celldblclick" : true,
5862 * Fires when a row is clicked
5863 * @param {Roo.bootstrap.Table} this
5864 * @param {Roo.Element} el
5865 * @param {Number} rowIndex
5866 * @param {Roo.EventObject} e
5870 * @event rowdblclick
5871 * Fires when a row is double clicked
5872 * @param {Roo.bootstrap.Table} this
5873 * @param {Roo.Element} el
5874 * @param {Number} rowIndex
5875 * @param {Roo.EventObject} e
5877 "rowdblclick" : true,
5880 * Fires when a mouseover occur
5881 * @param {Roo.bootstrap.Table} this
5882 * @param {Roo.Element} el
5883 * @param {Number} rowIndex
5884 * @param {Number} columnIndex
5885 * @param {Roo.EventObject} e
5890 * Fires when a mouseout occur
5891 * @param {Roo.bootstrap.Table} this
5892 * @param {Roo.Element} el
5893 * @param {Number} rowIndex
5894 * @param {Number} columnIndex
5895 * @param {Roo.EventObject} e
5900 * Fires when a row is rendered, so you can change add a style to it.
5901 * @param {Roo.bootstrap.Table} this
5902 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5906 * @event rowsrendered
5907 * Fires when all the rows have been rendered
5908 * @param {Roo.bootstrap.Table} this
5910 'rowsrendered' : true,
5912 * @event contextmenu
5913 * The raw contextmenu event for the entire grid.
5914 * @param {Roo.EventObject} e
5916 "contextmenu" : true,
5918 * @event rowcontextmenu
5919 * Fires when a row is right clicked
5920 * @param {Roo.bootstrap.Table} this
5921 * @param {Number} rowIndex
5922 * @param {Roo.EventObject} e
5924 "rowcontextmenu" : true,
5926 * @event cellcontextmenu
5927 * Fires when a cell is right clicked
5928 * @param {Roo.bootstrap.Table} this
5929 * @param {Number} rowIndex
5930 * @param {Number} cellIndex
5931 * @param {Roo.EventObject} e
5933 "cellcontextmenu" : true,
5935 * @event headercontextmenu
5936 * Fires when a header is right clicked
5937 * @param {Roo.bootstrap.Table} this
5938 * @param {Number} columnIndex
5939 * @param {Roo.EventObject} e
5941 "headercontextmenu" : true
5945 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5971 rowSelection : false,
5972 cellSelection : false,
5975 // Roo.Element - the tbody
5977 // Roo.Element - thead element
5980 container: false, // used by gridpanel...
5984 getAutoCreate : function()
5986 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5993 if (this.scrollBody) {
5994 cfg.cls += ' table-body-fixed';
5997 cfg.cls += ' table-striped';
6001 cfg.cls += ' table-hover';
6003 if (this.bordered) {
6004 cfg.cls += ' table-bordered';
6006 if (this.condensed) {
6007 cfg.cls += ' table-condensed';
6009 if (this.responsive) {
6010 cfg.cls += ' table-responsive';
6014 cfg.cls+= ' ' +this.cls;
6017 // this lot should be simplifed...
6020 cfg.align=this.align;
6023 cfg.bgcolor=this.bgcolor;
6026 cfg.border=this.border;
6028 if (this.cellpadding) {
6029 cfg.cellpadding=this.cellpadding;
6031 if (this.cellspacing) {
6032 cfg.cellspacing=this.cellspacing;
6035 cfg.frame=this.frame;
6038 cfg.rules=this.rules;
6040 if (this.sortable) {
6041 cfg.sortable=this.sortable;
6044 cfg.summary=this.summary;
6047 cfg.width=this.width;
6050 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6053 if(this.store || this.cm){
6054 if(this.headerShow){
6055 cfg.cn.push(this.renderHeader());
6058 cfg.cn.push(this.renderBody());
6060 if(this.footerShow){
6061 cfg.cn.push(this.renderFooter());
6063 // where does this come from?
6064 //cfg.cls+= ' TableGrid';
6067 return { cn : [ cfg ] };
6070 initEvents : function()
6072 if(!this.store || !this.cm){
6075 if (this.selModel) {
6076 this.selModel.initEvents();
6080 //Roo.log('initEvents with ds!!!!');
6082 this.mainBody = this.el.select('tbody', true).first();
6083 this.mainHead = this.el.select('thead', true).first();
6090 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6091 e.on('click', _this.sort, _this);
6094 this.mainBody.on("click", this.onClick, this);
6095 this.mainBody.on("dblclick", this.onDblClick, this);
6097 // why is this done????? = it breaks dialogs??
6098 //this.parent().el.setStyle('position', 'relative');
6102 this.footer.parentId = this.id;
6103 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6106 this.el.select('tfoot tr td').first().addClass('hide');
6110 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6112 this.store.on('load', this.onLoad, this);
6113 this.store.on('beforeload', this.onBeforeLoad, this);
6114 this.store.on('update', this.onUpdate, this);
6115 this.store.on('add', this.onAdd, this);
6116 this.store.on("clear", this.clear, this);
6118 this.el.on("contextmenu", this.onContextMenu, this);
6120 this.mainBody.on('scroll', this.onBodyScroll, this);
6125 onContextMenu : function(e, t)
6127 this.processEvent("contextmenu", e);
6130 processEvent : function(name, e)
6132 if (name != 'touchstart' ) {
6133 this.fireEvent(name, e);
6136 var t = e.getTarget();
6138 var cell = Roo.get(t);
6144 if(cell.findParent('tfoot', false, true)){
6148 if(cell.findParent('thead', false, true)){
6150 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6151 cell = Roo.get(t).findParent('th', false, true);
6153 Roo.log("failed to find th in thead?");
6154 Roo.log(e.getTarget());
6159 var cellIndex = cell.dom.cellIndex;
6161 var ename = name == 'touchstart' ? 'click' : name;
6162 this.fireEvent("header" + ename, this, cellIndex, e);
6167 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6168 cell = Roo.get(t).findParent('td', false, true);
6170 Roo.log("failed to find th in tbody?");
6171 Roo.log(e.getTarget());
6176 var row = cell.findParent('tr', false, true);
6177 var cellIndex = cell.dom.cellIndex;
6178 var rowIndex = row.dom.rowIndex - 1;
6182 this.fireEvent("row" + name, this, rowIndex, e);
6186 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6192 onMouseover : function(e, el)
6194 var cell = Roo.get(el);
6200 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6201 cell = cell.findParent('td', false, true);
6204 var row = cell.findParent('tr', false, true);
6205 var cellIndex = cell.dom.cellIndex;
6206 var rowIndex = row.dom.rowIndex - 1; // start from 0
6208 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6212 onMouseout : function(e, el)
6214 var cell = Roo.get(el);
6220 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6221 cell = cell.findParent('td', false, true);
6224 var row = cell.findParent('tr', false, true);
6225 var cellIndex = cell.dom.cellIndex;
6226 var rowIndex = row.dom.rowIndex - 1; // start from 0
6228 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6232 onClick : function(e, el)
6234 var cell = Roo.get(el);
6236 if(!cell || (!this.cellSelection && !this.rowSelection)){
6240 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6241 cell = cell.findParent('td', false, true);
6244 if(!cell || typeof(cell) == 'undefined'){
6248 var row = cell.findParent('tr', false, true);
6250 if(!row || typeof(row) == 'undefined'){
6254 var cellIndex = cell.dom.cellIndex;
6255 var rowIndex = this.getRowIndex(row);
6257 // why??? - should these not be based on SelectionModel?
6258 if(this.cellSelection){
6259 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6262 if(this.rowSelection){
6263 this.fireEvent('rowclick', this, row, rowIndex, e);
6269 onDblClick : function(e,el)
6271 var cell = Roo.get(el);
6273 if(!cell || (!this.cellSelection && !this.rowSelection)){
6277 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6278 cell = cell.findParent('td', false, true);
6281 if(!cell || typeof(cell) == 'undefined'){
6285 var row = cell.findParent('tr', false, true);
6287 if(!row || typeof(row) == 'undefined'){
6291 var cellIndex = cell.dom.cellIndex;
6292 var rowIndex = this.getRowIndex(row);
6294 if(this.cellSelection){
6295 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6298 if(this.rowSelection){
6299 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6303 sort : function(e,el)
6305 var col = Roo.get(el);
6307 if(!col.hasClass('sortable')){
6311 var sort = col.attr('sort');
6314 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6318 this.store.sortInfo = {field : sort, direction : dir};
6321 Roo.log("calling footer first");
6322 this.footer.onClick('first');
6325 this.store.load({ params : { start : 0 } });
6329 renderHeader : function()
6337 this.totalWidth = 0;
6339 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6341 var config = cm.config[i];
6346 html: cm.getColumnHeader(i)
6351 if(typeof(config.sortable) != 'undefined' && config.sortable){
6353 c.html = '<i class="glyphicon"></i>' + c.html;
6356 if(typeof(config.lgHeader) != 'undefined'){
6357 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6360 if(typeof(config.mdHeader) != 'undefined'){
6361 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6364 if(typeof(config.smHeader) != 'undefined'){
6365 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6368 if(typeof(config.xsHeader) != 'undefined'){
6369 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6376 if(typeof(config.tooltip) != 'undefined'){
6377 c.tooltip = config.tooltip;
6380 if(typeof(config.colspan) != 'undefined'){
6381 c.colspan = config.colspan;
6384 if(typeof(config.hidden) != 'undefined' && config.hidden){
6385 c.style += ' display:none;';
6388 if(typeof(config.dataIndex) != 'undefined'){
6389 c.sort = config.dataIndex;
6394 if(typeof(config.align) != 'undefined' && config.align.length){
6395 c.style += ' text-align:' + config.align + ';';
6398 if(typeof(config.width) != 'undefined'){
6399 c.style += ' width:' + config.width + 'px;';
6400 this.totalWidth += config.width;
6402 this.totalWidth += 100; // assume minimum of 100 per column?
6405 if(typeof(config.cls) != 'undefined'){
6406 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6409 ['xs','sm','md','lg'].map(function(size){
6411 if(typeof(config[size]) == 'undefined'){
6415 if (!config[size]) { // 0 = hidden
6416 c.cls += ' hidden-' + size;
6420 c.cls += ' col-' + size + '-' + config[size];
6430 renderBody : function()
6440 colspan : this.cm.getColumnCount()
6450 renderFooter : function()
6460 colspan : this.cm.getColumnCount()
6474 // Roo.log('ds onload');
6479 var ds = this.store;
6481 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6482 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6483 if (_this.store.sortInfo) {
6485 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6486 e.select('i', true).addClass(['glyphicon-arrow-up']);
6489 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6490 e.select('i', true).addClass(['glyphicon-arrow-down']);
6495 var tbody = this.mainBody;
6497 if(ds.getCount() > 0){
6498 ds.data.each(function(d,rowIndex){
6499 var row = this.renderRow(cm, ds, rowIndex);
6501 tbody.createChild(row);
6505 if(row.cellObjects.length){
6506 Roo.each(row.cellObjects, function(r){
6507 _this.renderCellObject(r);
6514 Roo.each(this.el.select('tbody td', true).elements, function(e){
6515 e.on('mouseover', _this.onMouseover, _this);
6518 Roo.each(this.el.select('tbody td', true).elements, function(e){
6519 e.on('mouseout', _this.onMouseout, _this);
6521 this.fireEvent('rowsrendered', this);
6522 //if(this.loadMask){
6523 // this.maskEl.hide();
6530 onUpdate : function(ds,record)
6532 this.refreshRow(record);
6536 onRemove : function(ds, record, index, isUpdate){
6537 if(isUpdate !== true){
6538 this.fireEvent("beforerowremoved", this, index, record);
6540 var bt = this.mainBody.dom;
6542 var rows = this.el.select('tbody > tr', true).elements;
6544 if(typeof(rows[index]) != 'undefined'){
6545 bt.removeChild(rows[index].dom);
6548 // if(bt.rows[index]){
6549 // bt.removeChild(bt.rows[index]);
6552 if(isUpdate !== true){
6553 //this.stripeRows(index);
6554 //this.syncRowHeights(index, index);
6556 this.fireEvent("rowremoved", this, index, record);
6560 onAdd : function(ds, records, rowIndex)
6562 //Roo.log('on Add called');
6563 // - note this does not handle multiple adding very well..
6564 var bt = this.mainBody.dom;
6565 for (var i =0 ; i < records.length;i++) {
6566 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6567 //Roo.log(records[i]);
6568 //Roo.log(this.store.getAt(rowIndex+i));
6569 this.insertRow(this.store, rowIndex + i, false);
6576 refreshRow : function(record){
6577 var ds = this.store, index;
6578 if(typeof record == 'number'){
6580 record = ds.getAt(index);
6582 index = ds.indexOf(record);
6584 this.insertRow(ds, index, true);
6586 this.onRemove(ds, record, index+1, true);
6588 //this.syncRowHeights(index, index);
6590 this.fireEvent("rowupdated", this, index, record);
6593 insertRow : function(dm, rowIndex, isUpdate){
6596 this.fireEvent("beforerowsinserted", this, rowIndex);
6598 //var s = this.getScrollState();
6599 var row = this.renderRow(this.cm, this.store, rowIndex);
6600 // insert before rowIndex..
6601 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6605 if(row.cellObjects.length){
6606 Roo.each(row.cellObjects, function(r){
6607 _this.renderCellObject(r);
6612 this.fireEvent("rowsinserted", this, rowIndex);
6613 //this.syncRowHeights(firstRow, lastRow);
6614 //this.stripeRows(firstRow);
6621 getRowDom : function(rowIndex)
6623 var rows = this.el.select('tbody > tr', true).elements;
6625 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6628 // returns the object tree for a tr..
6631 renderRow : function(cm, ds, rowIndex)
6634 var d = ds.getAt(rowIndex);
6641 var cellObjects = [];
6643 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6644 var config = cm.config[i];
6646 var renderer = cm.getRenderer(i);
6650 if(typeof(renderer) !== 'undefined'){
6651 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6653 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6654 // and are rendered into the cells after the row is rendered - using the id for the element.
6656 if(typeof(value) === 'object'){
6666 rowIndex : rowIndex,
6671 this.fireEvent('rowclass', this, rowcfg);
6675 cls : rowcfg.rowClass,
6677 html: (typeof(value) === 'object') ? '' : value
6684 if(typeof(config.colspan) != 'undefined'){
6685 td.colspan = config.colspan;
6688 if(typeof(config.hidden) != 'undefined' && config.hidden){
6689 td.style += ' display:none;';
6692 if(typeof(config.align) != 'undefined' && config.align.length){
6693 td.style += ' text-align:' + config.align + ';';
6696 if(typeof(config.width) != 'undefined'){
6697 td.style += ' width:' + config.width + 'px;';
6700 if(typeof(config.cursor) != 'undefined'){
6701 td.style += ' cursor:' + config.cursor + ';';
6704 if(typeof(config.cls) != 'undefined'){
6705 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6708 ['xs','sm','md','lg'].map(function(size){
6710 if(typeof(config[size]) == 'undefined'){
6714 if (!config[size]) { // 0 = hidden
6715 td.cls += ' hidden-' + size;
6719 td.cls += ' col-' + size + '-' + config[size];
6727 row.cellObjects = cellObjects;
6735 onBeforeLoad : function()
6737 //Roo.log('ds onBeforeLoad');
6741 //if(this.loadMask){
6742 // this.maskEl.show();
6750 this.el.select('tbody', true).first().dom.innerHTML = '';
6753 * Show or hide a row.
6754 * @param {Number} rowIndex to show or hide
6755 * @param {Boolean} state hide
6757 setRowVisibility : function(rowIndex, state)
6759 var bt = this.mainBody.dom;
6761 var rows = this.el.select('tbody > tr', true).elements;
6763 if(typeof(rows[rowIndex]) == 'undefined'){
6766 rows[rowIndex].dom.style.display = state ? '' : 'none';
6770 getSelectionModel : function(){
6772 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6774 return this.selModel;
6777 * Render the Roo.bootstrap object from renderder
6779 renderCellObject : function(r)
6783 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6785 var t = r.cfg.render(r.container);
6788 Roo.each(r.cfg.cn, function(c){
6790 container: t.getChildContainer(),
6793 _this.renderCellObject(child);
6798 getRowIndex : function(row)
6802 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6813 * Returns the grid's underlying element = used by panel.Grid
6814 * @return {Element} The element
6816 getGridEl : function(){
6820 * Forces a resize - used by panel.Grid
6821 * @return {Element} The element
6823 autoSize : function()
6825 //var ctr = Roo.get(this.container.dom.parentElement);
6826 var ctr = Roo.get(this.el.dom);
6828 var thd = this.getGridEl().select('thead',true).first();
6829 var tbd = this.getGridEl().select('tbody', true).first();
6830 var tfd = this.getGridEl().select('tfoot', true).first();
6832 var cw = ctr.getWidth();
6836 tbd.setSize(ctr.getWidth(),
6837 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6839 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6842 cw = Math.max(cw, this.totalWidth);
6843 this.getGridEl().select('tr',true).setWidth(cw);
6844 // resize 'expandable coloumn?
6846 return; // we doe not have a view in this design..
6849 onBodyScroll: function()
6851 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6852 this.mainHead.setStyle({
6853 'position' : 'relative',
6854 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6859 var scrollHeight = this.mainBody.dom.scrollHeight;
6861 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6863 var height = this.mainBody.getHeight();
6865 if(scrollHeight - height == scrollTop) {
6867 var total = this.ds.getTotalCount();
6869 if(this.footer.cursor + this.footer.pageSize < total){
6871 this.footer.ds.load({
6873 start : this.footer.cursor + this.footer.pageSize,
6874 limit : this.footer.pageSize
6895 * @class Roo.bootstrap.TableCell
6896 * @extends Roo.bootstrap.Component
6897 * Bootstrap TableCell class
6898 * @cfg {String} html cell contain text
6899 * @cfg {String} cls cell class
6900 * @cfg {String} tag cell tag (td|th) default td
6901 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6902 * @cfg {String} align Aligns the content in a cell
6903 * @cfg {String} axis Categorizes cells
6904 * @cfg {String} bgcolor Specifies the background color of a cell
6905 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6906 * @cfg {Number} colspan Specifies the number of columns a cell should span
6907 * @cfg {String} headers Specifies one or more header cells a cell is related to
6908 * @cfg {Number} height Sets the height of a cell
6909 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6910 * @cfg {Number} rowspan Sets the number of rows a cell should span
6911 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6912 * @cfg {String} valign Vertical aligns the content in a cell
6913 * @cfg {Number} width Specifies the width of a cell
6916 * Create a new TableCell
6917 * @param {Object} config The config object
6920 Roo.bootstrap.TableCell = function(config){
6921 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6924 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6944 getAutoCreate : function(){
6945 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6965 cfg.align=this.align
6971 cfg.bgcolor=this.bgcolor
6974 cfg.charoff=this.charoff
6977 cfg.colspan=this.colspan
6980 cfg.headers=this.headers
6983 cfg.height=this.height
6986 cfg.nowrap=this.nowrap
6989 cfg.rowspan=this.rowspan
6992 cfg.scope=this.scope
6995 cfg.valign=this.valign
6998 cfg.width=this.width
7017 * @class Roo.bootstrap.TableRow
7018 * @extends Roo.bootstrap.Component
7019 * Bootstrap TableRow class
7020 * @cfg {String} cls row class
7021 * @cfg {String} align Aligns the content in a table row
7022 * @cfg {String} bgcolor Specifies a background color for a table row
7023 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7024 * @cfg {String} valign Vertical aligns the content in a table row
7027 * Create a new TableRow
7028 * @param {Object} config The config object
7031 Roo.bootstrap.TableRow = function(config){
7032 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7035 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7043 getAutoCreate : function(){
7044 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7054 cfg.align = this.align;
7057 cfg.bgcolor = this.bgcolor;
7060 cfg.charoff = this.charoff;
7063 cfg.valign = this.valign;
7081 * @class Roo.bootstrap.TableBody
7082 * @extends Roo.bootstrap.Component
7083 * Bootstrap TableBody class
7084 * @cfg {String} cls element class
7085 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7086 * @cfg {String} align Aligns the content inside the element
7087 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7088 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7091 * Create a new TableBody
7092 * @param {Object} config The config object
7095 Roo.bootstrap.TableBody = function(config){
7096 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7099 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7107 getAutoCreate : function(){
7108 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7122 cfg.align = this.align;
7125 cfg.charoff = this.charoff;
7128 cfg.valign = this.valign;
7135 // initEvents : function()
7142 // this.store = Roo.factory(this.store, Roo.data);
7143 // this.store.on('load', this.onLoad, this);
7145 // this.store.load();
7149 // onLoad: function ()
7151 // this.fireEvent('load', this);
7161 * Ext JS Library 1.1.1
7162 * Copyright(c) 2006-2007, Ext JS, LLC.
7164 * Originally Released Under LGPL - original licence link has changed is not relivant.
7167 * <script type="text/javascript">
7170 // as we use this in bootstrap.
7171 Roo.namespace('Roo.form');
7173 * @class Roo.form.Action
7174 * Internal Class used to handle form actions
7176 * @param {Roo.form.BasicForm} el The form element or its id
7177 * @param {Object} config Configuration options
7182 // define the action interface
7183 Roo.form.Action = function(form, options){
7185 this.options = options || {};
7188 * Client Validation Failed
7191 Roo.form.Action.CLIENT_INVALID = 'client';
7193 * Server Validation Failed
7196 Roo.form.Action.SERVER_INVALID = 'server';
7198 * Connect to Server Failed
7201 Roo.form.Action.CONNECT_FAILURE = 'connect';
7203 * Reading Data from Server Failed
7206 Roo.form.Action.LOAD_FAILURE = 'load';
7208 Roo.form.Action.prototype = {
7210 failureType : undefined,
7211 response : undefined,
7215 run : function(options){
7220 success : function(response){
7225 handleResponse : function(response){
7229 // default connection failure
7230 failure : function(response){
7232 this.response = response;
7233 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7234 this.form.afterAction(this, false);
7237 processResponse : function(response){
7238 this.response = response;
7239 if(!response.responseText){
7242 this.result = this.handleResponse(response);
7246 // utility functions used internally
7247 getUrl : function(appendParams){
7248 var url = this.options.url || this.form.url || this.form.el.dom.action;
7250 var p = this.getParams();
7252 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7258 getMethod : function(){
7259 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7262 getParams : function(){
7263 var bp = this.form.baseParams;
7264 var p = this.options.params;
7266 if(typeof p == "object"){
7267 p = Roo.urlEncode(Roo.applyIf(p, bp));
7268 }else if(typeof p == 'string' && bp){
7269 p += '&' + Roo.urlEncode(bp);
7272 p = Roo.urlEncode(bp);
7277 createCallback : function(){
7279 success: this.success,
7280 failure: this.failure,
7282 timeout: (this.form.timeout*1000),
7283 upload: this.form.fileUpload ? this.success : undefined
7288 Roo.form.Action.Submit = function(form, options){
7289 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7292 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7295 haveProgress : false,
7296 uploadComplete : false,
7298 // uploadProgress indicator.
7299 uploadProgress : function()
7301 if (!this.form.progressUrl) {
7305 if (!this.haveProgress) {
7306 Roo.MessageBox.progress("Uploading", "Uploading");
7308 if (this.uploadComplete) {
7309 Roo.MessageBox.hide();
7313 this.haveProgress = true;
7315 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7317 var c = new Roo.data.Connection();
7319 url : this.form.progressUrl,
7324 success : function(req){
7325 //console.log(data);
7329 rdata = Roo.decode(req.responseText)
7331 Roo.log("Invalid data from server..");
7335 if (!rdata || !rdata.success) {
7337 Roo.MessageBox.alert(Roo.encode(rdata));
7340 var data = rdata.data;
7342 if (this.uploadComplete) {
7343 Roo.MessageBox.hide();
7348 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7349 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7352 this.uploadProgress.defer(2000,this);
7355 failure: function(data) {
7356 Roo.log('progress url failed ');
7367 // run get Values on the form, so it syncs any secondary forms.
7368 this.form.getValues();
7370 var o = this.options;
7371 var method = this.getMethod();
7372 var isPost = method == 'POST';
7373 if(o.clientValidation === false || this.form.isValid()){
7375 if (this.form.progressUrl) {
7376 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7377 (new Date() * 1) + '' + Math.random());
7382 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7383 form:this.form.el.dom,
7384 url:this.getUrl(!isPost),
7386 params:isPost ? this.getParams() : null,
7387 isUpload: this.form.fileUpload
7390 this.uploadProgress();
7392 }else if (o.clientValidation !== false){ // client validation failed
7393 this.failureType = Roo.form.Action.CLIENT_INVALID;
7394 this.form.afterAction(this, false);
7398 success : function(response)
7400 this.uploadComplete= true;
7401 if (this.haveProgress) {
7402 Roo.MessageBox.hide();
7406 var result = this.processResponse(response);
7407 if(result === true || result.success){
7408 this.form.afterAction(this, true);
7412 this.form.markInvalid(result.errors);
7413 this.failureType = Roo.form.Action.SERVER_INVALID;
7415 this.form.afterAction(this, false);
7417 failure : function(response)
7419 this.uploadComplete= true;
7420 if (this.haveProgress) {
7421 Roo.MessageBox.hide();
7424 this.response = response;
7425 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7426 this.form.afterAction(this, false);
7429 handleResponse : function(response){
7430 if(this.form.errorReader){
7431 var rs = this.form.errorReader.read(response);
7434 for(var i = 0, len = rs.records.length; i < len; i++) {
7435 var r = rs.records[i];
7439 if(errors.length < 1){
7443 success : rs.success,
7449 ret = Roo.decode(response.responseText);
7453 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7463 Roo.form.Action.Load = function(form, options){
7464 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7465 this.reader = this.form.reader;
7468 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7473 Roo.Ajax.request(Roo.apply(
7474 this.createCallback(), {
7475 method:this.getMethod(),
7476 url:this.getUrl(false),
7477 params:this.getParams()
7481 success : function(response){
7483 var result = this.processResponse(response);
7484 if(result === true || !result.success || !result.data){
7485 this.failureType = Roo.form.Action.LOAD_FAILURE;
7486 this.form.afterAction(this, false);
7489 this.form.clearInvalid();
7490 this.form.setValues(result.data);
7491 this.form.afterAction(this, true);
7494 handleResponse : function(response){
7495 if(this.form.reader){
7496 var rs = this.form.reader.read(response);
7497 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7499 success : rs.success,
7503 return Roo.decode(response.responseText);
7507 Roo.form.Action.ACTION_TYPES = {
7508 'load' : Roo.form.Action.Load,
7509 'submit' : Roo.form.Action.Submit
7518 * @class Roo.bootstrap.Form
7519 * @extends Roo.bootstrap.Component
7520 * Bootstrap Form class
7521 * @cfg {String} method GET | POST (default POST)
7522 * @cfg {String} labelAlign top | left (default top)
7523 * @cfg {String} align left | right - for navbars
7524 * @cfg {Boolean} loadMask load mask when submit (default true)
7529 * @param {Object} config The config object
7533 Roo.bootstrap.Form = function(config){
7534 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7536 Roo.bootstrap.Form.popover.apply();
7540 * @event clientvalidation
7541 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7542 * @param {Form} this
7543 * @param {Boolean} valid true if the form has passed client-side validation
7545 clientvalidation: true,
7547 * @event beforeaction
7548 * Fires before any action is performed. Return false to cancel the action.
7549 * @param {Form} this
7550 * @param {Action} action The action to be performed
7554 * @event actionfailed
7555 * Fires when an action fails.
7556 * @param {Form} this
7557 * @param {Action} action The action that failed
7559 actionfailed : true,
7561 * @event actioncomplete
7562 * Fires when an action is completed.
7563 * @param {Form} this
7564 * @param {Action} action The action that completed
7566 actioncomplete : true
7571 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7574 * @cfg {String} method
7575 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7580 * The URL to use for form actions if one isn't supplied in the action options.
7583 * @cfg {Boolean} fileUpload
7584 * Set to true if this form is a file upload.
7588 * @cfg {Object} baseParams
7589 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7593 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7597 * @cfg {Sting} align (left|right) for navbar forms
7602 activeAction : null,
7605 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7606 * element by passing it or its id or mask the form itself by passing in true.
7609 waitMsgTarget : false,
7614 * @cfg {Boolean} errorMask (true|false) default false
7619 * @cfg {Number} maskOffset Default 100
7624 * @cfg {Boolean} maskBody
7628 getAutoCreate : function(){
7632 method : this.method || 'POST',
7633 id : this.id || Roo.id(),
7636 if (this.parent().xtype.match(/^Nav/)) {
7637 cfg.cls = 'navbar-form navbar-' + this.align;
7641 if (this.labelAlign == 'left' ) {
7642 cfg.cls += ' form-horizontal';
7648 initEvents : function()
7650 this.el.on('submit', this.onSubmit, this);
7651 // this was added as random key presses on the form where triggering form submit.
7652 this.el.on('keypress', function(e) {
7653 if (e.getCharCode() != 13) {
7656 // we might need to allow it for textareas.. and some other items.
7657 // check e.getTarget().
7659 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7663 Roo.log("keypress blocked");
7671 onSubmit : function(e){
7676 * Returns true if client-side validation on the form is successful.
7679 isValid : function(){
7680 var items = this.getItems();
7684 items.each(function(f){
7690 if(!target && f.el.isVisible(true)){
7696 if(this.errorMask && !valid){
7697 Roo.bootstrap.Form.popover.mask(this, target);
7704 * Returns true if any fields in this form have changed since their original load.
7707 isDirty : function(){
7709 var items = this.getItems();
7710 items.each(function(f){
7720 * Performs a predefined action (submit or load) or custom actions you define on this form.
7721 * @param {String} actionName The name of the action type
7722 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7723 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7724 * accept other config options):
7726 Property Type Description
7727 ---------------- --------------- ----------------------------------------------------------------------------------
7728 url String The url for the action (defaults to the form's url)
7729 method String The form method to use (defaults to the form's method, or POST if not defined)
7730 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7731 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7732 validate the form on the client (defaults to false)
7734 * @return {BasicForm} this
7736 doAction : function(action, options){
7737 if(typeof action == 'string'){
7738 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7740 if(this.fireEvent('beforeaction', this, action) !== false){
7741 this.beforeAction(action);
7742 action.run.defer(100, action);
7748 beforeAction : function(action){
7749 var o = action.options;
7754 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7756 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7759 // not really supported yet.. ??
7761 //if(this.waitMsgTarget === true){
7762 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7763 //}else if(this.waitMsgTarget){
7764 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7765 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7767 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7773 afterAction : function(action, success){
7774 this.activeAction = null;
7775 var o = action.options;
7780 Roo.get(document.body).unmask();
7786 //if(this.waitMsgTarget === true){
7787 // this.el.unmask();
7788 //}else if(this.waitMsgTarget){
7789 // this.waitMsgTarget.unmask();
7791 // Roo.MessageBox.updateProgress(1);
7792 // Roo.MessageBox.hide();
7799 Roo.callback(o.success, o.scope, [this, action]);
7800 this.fireEvent('actioncomplete', this, action);
7804 // failure condition..
7805 // we have a scenario where updates need confirming.
7806 // eg. if a locking scenario exists..
7807 // we look for { errors : { needs_confirm : true }} in the response.
7809 (typeof(action.result) != 'undefined') &&
7810 (typeof(action.result.errors) != 'undefined') &&
7811 (typeof(action.result.errors.needs_confirm) != 'undefined')
7814 Roo.log("not supported yet");
7817 Roo.MessageBox.confirm(
7818 "Change requires confirmation",
7819 action.result.errorMsg,
7824 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7834 Roo.callback(o.failure, o.scope, [this, action]);
7835 // show an error message if no failed handler is set..
7836 if (!this.hasListener('actionfailed')) {
7837 Roo.log("need to add dialog support");
7839 Roo.MessageBox.alert("Error",
7840 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7841 action.result.errorMsg :
7842 "Saving Failed, please check your entries or try again"
7847 this.fireEvent('actionfailed', this, action);
7852 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7853 * @param {String} id The value to search for
7856 findField : function(id){
7857 var items = this.getItems();
7858 var field = items.get(id);
7860 items.each(function(f){
7861 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7868 return field || null;
7871 * Mark fields in this form invalid in bulk.
7872 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7873 * @return {BasicForm} this
7875 markInvalid : function(errors){
7876 if(errors instanceof Array){
7877 for(var i = 0, len = errors.length; i < len; i++){
7878 var fieldError = errors[i];
7879 var f = this.findField(fieldError.id);
7881 f.markInvalid(fieldError.msg);
7887 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7888 field.markInvalid(errors[id]);
7892 //Roo.each(this.childForms || [], function (f) {
7893 // f.markInvalid(errors);
7900 * Set values for fields in this form in bulk.
7901 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7902 * @return {BasicForm} this
7904 setValues : function(values){
7905 if(values instanceof Array){ // array of objects
7906 for(var i = 0, len = values.length; i < len; i++){
7908 var f = this.findField(v.id);
7910 f.setValue(v.value);
7911 if(this.trackResetOnLoad){
7912 f.originalValue = f.getValue();
7916 }else{ // object hash
7919 if(typeof values[id] != 'function' && (field = this.findField(id))){
7921 if (field.setFromData &&
7923 field.displayField &&
7924 // combos' with local stores can
7925 // be queried via setValue()
7926 // to set their value..
7927 (field.store && !field.store.isLocal)
7931 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7932 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7933 field.setFromData(sd);
7935 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
7937 field.setFromData(values);
7940 field.setValue(values[id]);
7944 if(this.trackResetOnLoad){
7945 field.originalValue = field.getValue();
7951 //Roo.each(this.childForms || [], function (f) {
7952 // f.setValues(values);
7959 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7960 * they are returned as an array.
7961 * @param {Boolean} asString
7964 getValues : function(asString){
7965 //if (this.childForms) {
7966 // copy values from the child forms
7967 // Roo.each(this.childForms, function (f) {
7968 // this.setValues(f.getValues());
7974 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7975 if(asString === true){
7978 return Roo.urlDecode(fs);
7982 * Returns the fields in this form as an object with key/value pairs.
7983 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7986 getFieldValues : function(with_hidden)
7988 var items = this.getItems();
7990 items.each(function(f){
7996 var v = f.getValue();
7998 if (f.inputType =='radio') {
7999 if (typeof(ret[f.getName()]) == 'undefined') {
8000 ret[f.getName()] = ''; // empty..
8003 if (!f.el.dom.checked) {
8011 if(f.xtype == 'MoneyField'){
8012 ret[f.currencyName] = f.getCurrency();
8015 // not sure if this supported any more..
8016 if ((typeof(v) == 'object') && f.getRawValue) {
8017 v = f.getRawValue() ; // dates..
8019 // combo boxes where name != hiddenName...
8020 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8021 ret[f.name] = f.getRawValue();
8023 ret[f.getName()] = v;
8030 * Clears all invalid messages in this form.
8031 * @return {BasicForm} this
8033 clearInvalid : function(){
8034 var items = this.getItems();
8036 items.each(function(f){
8047 * @return {BasicForm} this
8050 var items = this.getItems();
8051 items.each(function(f){
8055 Roo.each(this.childForms || [], function (f) {
8063 getItems : function()
8065 var r=new Roo.util.MixedCollection(false, function(o){
8066 return o.id || (o.id = Roo.id());
8068 var iter = function(el) {
8075 Roo.each(el.items,function(e) {
8089 Roo.apply(Roo.bootstrap.Form, {
8116 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8117 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8118 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8119 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8122 this.maskEl.top.enableDisplayMode("block");
8123 this.maskEl.left.enableDisplayMode("block");
8124 this.maskEl.bottom.enableDisplayMode("block");
8125 this.maskEl.right.enableDisplayMode("block");
8127 this.toolTip = new Roo.bootstrap.Tooltip({
8128 cls : 'roo-form-error-popover',
8130 'left' : ['r-l', [-2,0], 'right'],
8131 'right' : ['l-r', [2,0], 'left'],
8132 'bottom' : ['tl-bl', [0,2], 'top'],
8133 'top' : [ 'bl-tl', [0,-2], 'bottom']
8137 this.toolTip.render(Roo.get(document.body));
8139 this.toolTip.el.enableDisplayMode("block");
8141 Roo.get(document.body).on('click', function(){
8145 Roo.get(document.body).on('touchstart', function(){
8149 this.isApplied = true
8152 mask : function(form, target)
8156 this.target = target;
8158 if(!this.form.errorMask || !target.el){
8162 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8164 Roo.log(scrollable);
8166 var ot = this.target.el.calcOffsetsTo(scrollable);
8168 var scrollTo = ot[1] - this.form.maskOffset;
8170 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8172 scrollable.scrollTo('top', scrollTo);
8174 var box = this.target.el.getBox();
8176 var zIndex = Roo.bootstrap.Modal.zIndex++;
8179 this.maskEl.top.setStyle('position', 'absolute');
8180 this.maskEl.top.setStyle('z-index', zIndex);
8181 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8182 this.maskEl.top.setLeft(0);
8183 this.maskEl.top.setTop(0);
8184 this.maskEl.top.show();
8186 this.maskEl.left.setStyle('position', 'absolute');
8187 this.maskEl.left.setStyle('z-index', zIndex);
8188 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8189 this.maskEl.left.setLeft(0);
8190 this.maskEl.left.setTop(box.y - this.padding);
8191 this.maskEl.left.show();
8193 this.maskEl.bottom.setStyle('position', 'absolute');
8194 this.maskEl.bottom.setStyle('z-index', zIndex);
8195 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8196 this.maskEl.bottom.setLeft(0);
8197 this.maskEl.bottom.setTop(box.bottom + this.padding);
8198 this.maskEl.bottom.show();
8200 this.maskEl.right.setStyle('position', 'absolute');
8201 this.maskEl.right.setStyle('z-index', zIndex);
8202 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8203 this.maskEl.right.setLeft(box.right + this.padding);
8204 this.maskEl.right.setTop(box.y - this.padding);
8205 this.maskEl.right.show();
8207 this.toolTip.bindEl = this.target.el;
8209 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8211 var tip = this.target.blankText;
8213 if(this.target.getValue() !== '' ) {
8215 if (this.target.invalidText.length) {
8216 tip = this.target.invalidText;
8217 } else if (this.target.regexText.length){
8218 tip = this.target.regexText;
8222 this.toolTip.show(tip);
8224 this.intervalID = window.setInterval(function() {
8225 Roo.bootstrap.Form.popover.unmask();
8228 window.onwheel = function(){ return false;};
8230 (function(){ this.isMasked = true; }).defer(500, this);
8236 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8240 this.maskEl.top.setStyle('position', 'absolute');
8241 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8242 this.maskEl.top.hide();
8244 this.maskEl.left.setStyle('position', 'absolute');
8245 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8246 this.maskEl.left.hide();
8248 this.maskEl.bottom.setStyle('position', 'absolute');
8249 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8250 this.maskEl.bottom.hide();
8252 this.maskEl.right.setStyle('position', 'absolute');
8253 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8254 this.maskEl.right.hide();
8256 this.toolTip.hide();
8258 this.toolTip.el.hide();
8260 window.onwheel = function(){ return true;};
8262 if(this.intervalID){
8263 window.clearInterval(this.intervalID);
8264 this.intervalID = false;
8267 this.isMasked = false;
8277 * Ext JS Library 1.1.1
8278 * Copyright(c) 2006-2007, Ext JS, LLC.
8280 * Originally Released Under LGPL - original licence link has changed is not relivant.
8283 * <script type="text/javascript">
8286 * @class Roo.form.VTypes
8287 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8290 Roo.form.VTypes = function(){
8291 // closure these in so they are only created once.
8292 var alpha = /^[a-zA-Z_]+$/;
8293 var alphanum = /^[a-zA-Z0-9_]+$/;
8294 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8295 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8297 // All these messages and functions are configurable
8300 * The function used to validate email addresses
8301 * @param {String} value The email address
8303 'email' : function(v){
8304 return email.test(v);
8307 * The error text to display when the email validation function returns false
8310 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8312 * The keystroke filter mask to be applied on email input
8315 'emailMask' : /[a-z0-9_\.\-@]/i,
8318 * The function used to validate URLs
8319 * @param {String} value The URL
8321 'url' : function(v){
8325 * The error text to display when the url validation function returns false
8328 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8331 * The function used to validate alpha values
8332 * @param {String} value The value
8334 'alpha' : function(v){
8335 return alpha.test(v);
8338 * The error text to display when the alpha validation function returns false
8341 'alphaText' : 'This field should only contain letters and _',
8343 * The keystroke filter mask to be applied on alpha input
8346 'alphaMask' : /[a-z_]/i,
8349 * The function used to validate alphanumeric values
8350 * @param {String} value The value
8352 'alphanum' : function(v){
8353 return alphanum.test(v);
8356 * The error text to display when the alphanumeric validation function returns false
8359 'alphanumText' : 'This field should only contain letters, numbers and _',
8361 * The keystroke filter mask to be applied on alphanumeric input
8364 'alphanumMask' : /[a-z0-9_]/i
8374 * @class Roo.bootstrap.Input
8375 * @extends Roo.bootstrap.Component
8376 * Bootstrap Input class
8377 * @cfg {Boolean} disabled is it disabled
8378 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8379 * @cfg {String} name name of the input
8380 * @cfg {string} fieldLabel - the label associated
8381 * @cfg {string} placeholder - placeholder to put in text.
8382 * @cfg {string} before - input group add on before
8383 * @cfg {string} after - input group add on after
8384 * @cfg {string} size - (lg|sm) or leave empty..
8385 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8386 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8387 * @cfg {Number} md colspan out of 12 for computer-sized screens
8388 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8389 * @cfg {string} value default value of the input
8390 * @cfg {Number} labelWidth set the width of label
8391 * @cfg {Number} labellg set the width of label (1-12)
8392 * @cfg {Number} labelmd set the width of label (1-12)
8393 * @cfg {Number} labelsm set the width of label (1-12)
8394 * @cfg {Number} labelxs set the width of label (1-12)
8395 * @cfg {String} labelAlign (top|left)
8396 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8397 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8398 * @cfg {String} indicatorpos (left|right) default left
8400 * @cfg {String} align (left|center|right) Default left
8401 * @cfg {Boolean} forceFeedback (true|false) Default false
8407 * Create a new Input
8408 * @param {Object} config The config object
8411 Roo.bootstrap.Input = function(config){
8413 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8418 * Fires when this field receives input focus.
8419 * @param {Roo.form.Field} this
8424 * Fires when this field loses input focus.
8425 * @param {Roo.form.Field} this
8430 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8431 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8432 * @param {Roo.form.Field} this
8433 * @param {Roo.EventObject} e The event object
8438 * Fires just before the field blurs if the field value has changed.
8439 * @param {Roo.form.Field} this
8440 * @param {Mixed} newValue The new value
8441 * @param {Mixed} oldValue The original value
8446 * Fires after the field has been marked as invalid.
8447 * @param {Roo.form.Field} this
8448 * @param {String} msg The validation message
8453 * Fires after the field has been validated with no errors.
8454 * @param {Roo.form.Field} this
8459 * Fires after the key up
8460 * @param {Roo.form.Field} this
8461 * @param {Roo.EventObject} e The event Object
8467 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8469 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8470 automatic validation (defaults to "keyup").
8472 validationEvent : "keyup",
8474 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8476 validateOnBlur : true,
8478 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8480 validationDelay : 250,
8482 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8484 focusClass : "x-form-focus", // not needed???
8488 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8490 invalidClass : "has-warning",
8493 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8495 validClass : "has-success",
8498 * @cfg {Boolean} hasFeedback (true|false) default true
8503 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8505 invalidFeedbackClass : "glyphicon-warning-sign",
8508 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8510 validFeedbackClass : "glyphicon-ok",
8513 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8515 selectOnFocus : false,
8518 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8522 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8527 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8529 disableKeyFilter : false,
8532 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8536 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8540 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8542 blankText : "Please complete this mandatory field",
8545 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8549 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8551 maxLength : Number.MAX_VALUE,
8553 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8555 minLengthText : "The minimum length for this field is {0}",
8557 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8559 maxLengthText : "The maximum length for this field is {0}",
8563 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8564 * If available, this function will be called only after the basic validators all return true, and will be passed the
8565 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8569 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8570 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8571 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8575 * @cfg {String} regexText -- Depricated - use Invalid Text
8580 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8586 autocomplete: false,
8605 formatedValue : false,
8606 forceFeedback : false,
8608 indicatorpos : 'left',
8615 parentLabelAlign : function()
8618 while (parent.parent()) {
8619 parent = parent.parent();
8620 if (typeof(parent.labelAlign) !='undefined') {
8621 return parent.labelAlign;
8628 getAutoCreate : function()
8630 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8636 if(this.inputType != 'hidden'){
8637 cfg.cls = 'form-group' //input-group
8643 type : this.inputType,
8645 cls : 'form-control',
8646 placeholder : this.placeholder || '',
8647 autocomplete : this.autocomplete || 'new-password'
8651 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8654 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8655 input.maxLength = this.maxLength;
8658 if (this.disabled) {
8659 input.disabled=true;
8662 if (this.readOnly) {
8663 input.readonly=true;
8667 input.name = this.name;
8671 input.cls += ' input-' + this.size;
8675 ['xs','sm','md','lg'].map(function(size){
8676 if (settings[size]) {
8677 cfg.cls += ' col-' + size + '-' + settings[size];
8681 var inputblock = input;
8685 cls: 'glyphicon form-control-feedback'
8688 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8691 cls : 'has-feedback',
8699 if (this.before || this.after) {
8702 cls : 'input-group',
8706 if (this.before && typeof(this.before) == 'string') {
8708 inputblock.cn.push({
8710 cls : 'roo-input-before input-group-addon',
8714 if (this.before && typeof(this.before) == 'object') {
8715 this.before = Roo.factory(this.before);
8717 inputblock.cn.push({
8719 cls : 'roo-input-before input-group-' +
8720 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8724 inputblock.cn.push(input);
8726 if (this.after && typeof(this.after) == 'string') {
8727 inputblock.cn.push({
8729 cls : 'roo-input-after input-group-addon',
8733 if (this.after && typeof(this.after) == 'object') {
8734 this.after = Roo.factory(this.after);
8736 inputblock.cn.push({
8738 cls : 'roo-input-after input-group-' +
8739 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8743 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8744 inputblock.cls += ' has-feedback';
8745 inputblock.cn.push(feedback);
8749 if (align ==='left' && this.fieldLabel.length) {
8751 cfg.cls += ' roo-form-group-label-left';
8756 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8757 tooltip : 'This field is required'
8762 cls : 'control-label',
8763 html : this.fieldLabel
8774 var labelCfg = cfg.cn[1];
8775 var contentCfg = cfg.cn[2];
8777 if(this.indicatorpos == 'right'){
8782 cls : 'control-label',
8786 html : this.fieldLabel
8790 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8791 tooltip : 'This field is required'
8804 labelCfg = cfg.cn[0];
8805 contentCfg = cfg.cn[1];
8809 if(this.labelWidth > 12){
8810 labelCfg.style = "width: " + this.labelWidth + 'px';
8813 if(this.labelWidth < 13 && this.labelmd == 0){
8814 this.labelmd = this.labelWidth;
8817 if(this.labellg > 0){
8818 labelCfg.cls += ' col-lg-' + this.labellg;
8819 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8822 if(this.labelmd > 0){
8823 labelCfg.cls += ' col-md-' + this.labelmd;
8824 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8827 if(this.labelsm > 0){
8828 labelCfg.cls += ' col-sm-' + this.labelsm;
8829 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8832 if(this.labelxs > 0){
8833 labelCfg.cls += ' col-xs-' + this.labelxs;
8834 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8838 } else if ( this.fieldLabel.length) {
8843 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8844 tooltip : 'This field is required'
8848 //cls : 'input-group-addon',
8849 html : this.fieldLabel
8857 if(this.indicatorpos == 'right'){
8862 //cls : 'input-group-addon',
8863 html : this.fieldLabel
8868 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8869 tooltip : 'This field is required'
8889 if (this.parentType === 'Navbar' && this.parent().bar) {
8890 cfg.cls += ' navbar-form';
8893 if (this.parentType === 'NavGroup') {
8894 cfg.cls += ' navbar-form';
8902 * return the real input element.
8904 inputEl: function ()
8906 return this.el.select('input.form-control',true).first();
8909 tooltipEl : function()
8911 return this.inputEl();
8914 indicatorEl : function()
8916 var indicator = this.el.select('i.roo-required-indicator',true).first();
8926 setDisabled : function(v)
8928 var i = this.inputEl().dom;
8930 i.removeAttribute('disabled');
8934 i.setAttribute('disabled','true');
8936 initEvents : function()
8939 this.inputEl().on("keydown" , this.fireKey, this);
8940 this.inputEl().on("focus", this.onFocus, this);
8941 this.inputEl().on("blur", this.onBlur, this);
8943 this.inputEl().relayEvent('keyup', this);
8945 this.indicator = this.indicatorEl();
8948 this.indicator.addClass('invisible');
8952 // reference to original value for reset
8953 this.originalValue = this.getValue();
8954 //Roo.form.TextField.superclass.initEvents.call(this);
8955 if(this.validationEvent == 'keyup'){
8956 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8957 this.inputEl().on('keyup', this.filterValidation, this);
8959 else if(this.validationEvent !== false){
8960 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8963 if(this.selectOnFocus){
8964 this.on("focus", this.preFocus, this);
8967 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8968 this.inputEl().on("keypress", this.filterKeys, this);
8970 this.inputEl().relayEvent('keypress', this);
8973 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8974 this.el.on("click", this.autoSize, this);
8977 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8978 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8981 if (typeof(this.before) == 'object') {
8982 this.before.render(this.el.select('.roo-input-before',true).first());
8984 if (typeof(this.after) == 'object') {
8985 this.after.render(this.el.select('.roo-input-after',true).first());
8990 filterValidation : function(e){
8991 if(!e.isNavKeyPress()){
8992 this.validationTask.delay(this.validationDelay);
8996 * Validates the field value
8997 * @return {Boolean} True if the value is valid, else false
8999 validate : function(){
9000 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9001 if(this.disabled || this.validateValue(this.getRawValue())){
9012 * Validates a value according to the field's validation rules and marks the field as invalid
9013 * if the validation fails
9014 * @param {Mixed} value The value to validate
9015 * @return {Boolean} True if the value is valid, else false
9017 validateValue : function(value){
9018 if(value.length < 1) { // if it's blank
9019 if(this.allowBlank){
9022 return this.inputEl().hasClass('hide') ? true : false;
9025 if(value.length < this.minLength){
9028 if(value.length > this.maxLength){
9032 var vt = Roo.form.VTypes;
9033 if(!vt[this.vtype](value, this)){
9037 if(typeof this.validator == "function"){
9038 var msg = this.validator(value);
9042 if (typeof(msg) == 'string') {
9043 this.invalidText = msg;
9047 if(this.regex && !this.regex.test(value)){
9057 fireKey : function(e){
9058 //Roo.log('field ' + e.getKey());
9059 if(e.isNavKeyPress()){
9060 this.fireEvent("specialkey", this, e);
9063 focus : function (selectText){
9065 this.inputEl().focus();
9066 if(selectText === true){
9067 this.inputEl().dom.select();
9073 onFocus : function(){
9074 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9075 // this.el.addClass(this.focusClass);
9078 this.hasFocus = true;
9079 this.startValue = this.getValue();
9080 this.fireEvent("focus", this);
9084 beforeBlur : Roo.emptyFn,
9088 onBlur : function(){
9090 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9091 //this.el.removeClass(this.focusClass);
9093 this.hasFocus = false;
9094 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9097 var v = this.getValue();
9098 if(String(v) !== String(this.startValue)){
9099 this.fireEvent('change', this, v, this.startValue);
9101 this.fireEvent("blur", this);
9105 * Resets the current field value to the originally loaded value and clears any validation messages
9108 this.setValue(this.originalValue);
9112 * Returns the name of the field
9113 * @return {Mixed} name The name field
9115 getName: function(){
9119 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9120 * @return {Mixed} value The field value
9122 getValue : function(){
9124 var v = this.inputEl().getValue();
9129 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9130 * @return {Mixed} value The field value
9132 getRawValue : function(){
9133 var v = this.inputEl().getValue();
9139 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9140 * @param {Mixed} value The value to set
9142 setRawValue : function(v){
9143 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9146 selectText : function(start, end){
9147 var v = this.getRawValue();
9149 start = start === undefined ? 0 : start;
9150 end = end === undefined ? v.length : end;
9151 var d = this.inputEl().dom;
9152 if(d.setSelectionRange){
9153 d.setSelectionRange(start, end);
9154 }else if(d.createTextRange){
9155 var range = d.createTextRange();
9156 range.moveStart("character", start);
9157 range.moveEnd("character", v.length-end);
9164 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9165 * @param {Mixed} value The value to set
9167 setValue : function(v){
9170 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9176 processValue : function(value){
9177 if(this.stripCharsRe){
9178 var newValue = value.replace(this.stripCharsRe, '');
9179 if(newValue !== value){
9180 this.setRawValue(newValue);
9187 preFocus : function(){
9189 if(this.selectOnFocus){
9190 this.inputEl().dom.select();
9193 filterKeys : function(e){
9195 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9198 var c = e.getCharCode(), cc = String.fromCharCode(c);
9199 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9202 if(!this.maskRe.test(cc)){
9207 * Clear any invalid styles/messages for this field
9209 clearInvalid : function(){
9211 if(!this.el || this.preventMark){ // not rendered
9216 this.el.removeClass(this.invalidClass);
9218 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9220 var feedback = this.el.select('.form-control-feedback', true).first();
9223 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9228 this.fireEvent('valid', this);
9232 * Mark this field as valid
9234 markValid : function()
9236 if(!this.el || this.preventMark){ // not rendered...
9240 this.el.removeClass([this.invalidClass, this.validClass]);
9242 var feedback = this.el.select('.form-control-feedback', true).first();
9245 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9252 if(this.allowBlank && !this.getRawValue().length){
9257 this.indicator.removeClass('visible');
9258 this.indicator.addClass('invisible');
9261 this.el.addClass(this.validClass);
9263 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9265 var feedback = this.el.select('.form-control-feedback', true).first();
9268 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9269 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9274 this.fireEvent('valid', this);
9278 * Mark this field as invalid
9279 * @param {String} msg The validation message
9281 markInvalid : function(msg)
9283 if(!this.el || this.preventMark){ // not rendered
9287 this.el.removeClass([this.invalidClass, this.validClass]);
9289 var feedback = this.el.select('.form-control-feedback', true).first();
9292 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9299 if(this.allowBlank && !this.getRawValue().length){
9304 this.indicator.removeClass('invisible');
9305 this.indicator.addClass('visible');
9308 this.el.addClass(this.invalidClass);
9310 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9312 var feedback = this.el.select('.form-control-feedback', true).first();
9315 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9317 if(this.getValue().length || this.forceFeedback){
9318 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9325 this.fireEvent('invalid', this, msg);
9328 SafariOnKeyDown : function(event)
9330 // this is a workaround for a password hang bug on chrome/ webkit.
9331 if (this.inputEl().dom.type != 'password') {
9335 var isSelectAll = false;
9337 if(this.inputEl().dom.selectionEnd > 0){
9338 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9340 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9341 event.preventDefault();
9346 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9348 event.preventDefault();
9349 // this is very hacky as keydown always get's upper case.
9351 var cc = String.fromCharCode(event.getCharCode());
9352 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9356 adjustWidth : function(tag, w){
9357 tag = tag.toLowerCase();
9358 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9359 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9363 if(tag == 'textarea'){
9366 }else if(Roo.isOpera){
9370 if(tag == 'textarea'){
9378 setFieldLabel : function(v)
9384 this.fieldLabel = v;
9387 var ar = this.el.select('label > span',true);
9388 if (!ar.elements.length) {
9389 Roo.log("could not find label > span on element");
9393 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9397 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9410 * @class Roo.bootstrap.TextArea
9411 * @extends Roo.bootstrap.Input
9412 * Bootstrap TextArea class
9413 * @cfg {Number} cols Specifies the visible width of a text area
9414 * @cfg {Number} rows Specifies the visible number of lines in a text area
9415 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9416 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9417 * @cfg {string} html text
9420 * Create a new TextArea
9421 * @param {Object} config The config object
9424 Roo.bootstrap.TextArea = function(config){
9425 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9429 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9439 getAutoCreate : function(){
9441 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9447 if(this.inputType != 'hidden'){
9448 cfg.cls = 'form-group' //input-group
9456 value : this.value || '',
9457 html: this.html || '',
9458 cls : 'form-control',
9459 placeholder : this.placeholder || ''
9463 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9464 input.maxLength = this.maxLength;
9468 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9472 input.cols = this.cols;
9475 if (this.readOnly) {
9476 input.readonly = true;
9480 input.name = this.name;
9484 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9488 ['xs','sm','md','lg'].map(function(size){
9489 if (settings[size]) {
9490 cfg.cls += ' col-' + size + '-' + settings[size];
9494 var inputblock = input;
9496 if(this.hasFeedback && !this.allowBlank){
9500 cls: 'glyphicon form-control-feedback'
9504 cls : 'has-feedback',
9513 if (this.before || this.after) {
9516 cls : 'input-group',
9520 inputblock.cn.push({
9522 cls : 'input-group-addon',
9527 inputblock.cn.push(input);
9529 if(this.hasFeedback && !this.allowBlank){
9530 inputblock.cls += ' has-feedback';
9531 inputblock.cn.push(feedback);
9535 inputblock.cn.push({
9537 cls : 'input-group-addon',
9544 if (align ==='left' && this.fieldLabel.length) {
9549 cls : 'control-label',
9550 html : this.fieldLabel
9561 if(this.labelWidth > 12){
9562 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9565 if(this.labelWidth < 13 && this.labelmd == 0){
9566 this.labelmd = this.labelWidth;
9569 if(this.labellg > 0){
9570 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9571 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9574 if(this.labelmd > 0){
9575 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9576 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9579 if(this.labelsm > 0){
9580 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9581 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9584 if(this.labelxs > 0){
9585 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9586 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9589 } else if ( this.fieldLabel.length) {
9594 //cls : 'input-group-addon',
9595 html : this.fieldLabel
9613 if (this.disabled) {
9614 input.disabled=true;
9621 * return the real textarea element.
9623 inputEl: function ()
9625 return this.el.select('textarea.form-control',true).first();
9629 * Clear any invalid styles/messages for this field
9631 clearInvalid : function()
9634 if(!this.el || this.preventMark){ // not rendered
9638 var label = this.el.select('label', true).first();
9639 var icon = this.el.select('i.fa-star', true).first();
9645 this.el.removeClass(this.invalidClass);
9647 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9649 var feedback = this.el.select('.form-control-feedback', true).first();
9652 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9657 this.fireEvent('valid', this);
9661 * Mark this field as valid
9663 markValid : function()
9665 if(!this.el || this.preventMark){ // not rendered
9669 this.el.removeClass([this.invalidClass, this.validClass]);
9671 var feedback = this.el.select('.form-control-feedback', true).first();
9674 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9677 if(this.disabled || this.allowBlank){
9681 var label = this.el.select('label', true).first();
9682 var icon = this.el.select('i.fa-star', true).first();
9688 this.el.addClass(this.validClass);
9690 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9692 var feedback = this.el.select('.form-control-feedback', true).first();
9695 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9696 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9701 this.fireEvent('valid', this);
9705 * Mark this field as invalid
9706 * @param {String} msg The validation message
9708 markInvalid : function(msg)
9710 if(!this.el || this.preventMark){ // not rendered
9714 this.el.removeClass([this.invalidClass, this.validClass]);
9716 var feedback = this.el.select('.form-control-feedback', true).first();
9719 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9722 if(this.disabled || this.allowBlank){
9726 var label = this.el.select('label', true).first();
9727 var icon = this.el.select('i.fa-star', true).first();
9729 if(!this.getValue().length && label && !icon){
9730 this.el.createChild({
9732 cls : 'text-danger fa fa-lg fa-star',
9733 tooltip : 'This field is required',
9734 style : 'margin-right:5px;'
9738 this.el.addClass(this.invalidClass);
9740 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9742 var feedback = this.el.select('.form-control-feedback', true).first();
9745 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9747 if(this.getValue().length || this.forceFeedback){
9748 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9755 this.fireEvent('invalid', this, msg);
9763 * trigger field - base class for combo..
9768 * @class Roo.bootstrap.TriggerField
9769 * @extends Roo.bootstrap.Input
9770 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9771 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9772 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9773 * for which you can provide a custom implementation. For example:
9775 var trigger = new Roo.bootstrap.TriggerField();
9776 trigger.onTriggerClick = myTriggerFn;
9777 trigger.applyTo('my-field');
9780 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9781 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9782 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9783 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9784 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9787 * Create a new TriggerField.
9788 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9789 * to the base TextField)
9791 Roo.bootstrap.TriggerField = function(config){
9792 this.mimicing = false;
9793 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9796 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9798 * @cfg {String} triggerClass A CSS class to apply to the trigger
9801 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9806 * @cfg {Boolean} removable (true|false) special filter default false
9810 /** @cfg {Boolean} grow @hide */
9811 /** @cfg {Number} growMin @hide */
9812 /** @cfg {Number} growMax @hide */
9818 autoSize: Roo.emptyFn,
9825 actionMode : 'wrap',
9830 getAutoCreate : function(){
9832 var align = this.labelAlign || this.parentLabelAlign();
9837 cls: 'form-group' //input-group
9844 type : this.inputType,
9845 cls : 'form-control',
9846 autocomplete: 'new-password',
9847 placeholder : this.placeholder || ''
9851 input.name = this.name;
9854 input.cls += ' input-' + this.size;
9857 if (this.disabled) {
9858 input.disabled=true;
9861 var inputblock = input;
9863 if(this.hasFeedback && !this.allowBlank){
9867 cls: 'glyphicon form-control-feedback'
9870 if(this.removable && !this.editable && !this.tickable){
9872 cls : 'has-feedback',
9878 cls : 'roo-combo-removable-btn close'
9885 cls : 'has-feedback',
9894 if(this.removable && !this.editable && !this.tickable){
9896 cls : 'roo-removable',
9902 cls : 'roo-combo-removable-btn close'
9909 if (this.before || this.after) {
9912 cls : 'input-group',
9916 inputblock.cn.push({
9918 cls : 'input-group-addon',
9923 inputblock.cn.push(input);
9925 if(this.hasFeedback && !this.allowBlank){
9926 inputblock.cls += ' has-feedback';
9927 inputblock.cn.push(feedback);
9931 inputblock.cn.push({
9933 cls : 'input-group-addon',
9946 cls: 'form-hidden-field'
9960 cls: 'form-hidden-field'
9964 cls: 'roo-select2-choices',
9968 cls: 'roo-select2-search-field',
9981 cls: 'roo-select2-container input-group',
9986 // cls: 'typeahead typeahead-long dropdown-menu',
9987 // style: 'display:none'
9992 if(!this.multiple && this.showToggleBtn){
9998 if (this.caret != false) {
10001 cls: 'fa fa-' + this.caret
10008 cls : 'input-group-addon btn dropdown-toggle',
10013 cls: 'combobox-clear',
10027 combobox.cls += ' roo-select2-container-multi';
10030 if (align ==='left' && this.fieldLabel.length) {
10032 cfg.cls += ' roo-form-group-label-left';
10037 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10038 tooltip : 'This field is required'
10043 cls : 'control-label',
10044 html : this.fieldLabel
10056 var labelCfg = cfg.cn[1];
10057 var contentCfg = cfg.cn[2];
10059 if(this.indicatorpos == 'right'){
10064 cls : 'control-label',
10068 html : this.fieldLabel
10072 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10073 tooltip : 'This field is required'
10086 labelCfg = cfg.cn[0];
10087 contentCfg = cfg.cn[1];
10090 if(this.labelWidth > 12){
10091 labelCfg.style = "width: " + this.labelWidth + 'px';
10094 if(this.labelWidth < 13 && this.labelmd == 0){
10095 this.labelmd = this.labelWidth;
10098 if(this.labellg > 0){
10099 labelCfg.cls += ' col-lg-' + this.labellg;
10100 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10103 if(this.labelmd > 0){
10104 labelCfg.cls += ' col-md-' + this.labelmd;
10105 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10108 if(this.labelsm > 0){
10109 labelCfg.cls += ' col-sm-' + this.labelsm;
10110 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10113 if(this.labelxs > 0){
10114 labelCfg.cls += ' col-xs-' + this.labelxs;
10115 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10118 } else if ( this.fieldLabel.length) {
10119 // Roo.log(" label");
10123 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10124 tooltip : 'This field is required'
10128 //cls : 'input-group-addon',
10129 html : this.fieldLabel
10137 if(this.indicatorpos == 'right'){
10145 html : this.fieldLabel
10149 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10150 tooltip : 'This field is required'
10163 // Roo.log(" no label && no align");
10170 ['xs','sm','md','lg'].map(function(size){
10171 if (settings[size]) {
10172 cfg.cls += ' col-' + size + '-' + settings[size];
10183 onResize : function(w, h){
10184 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10185 // if(typeof w == 'number'){
10186 // var x = w - this.trigger.getWidth();
10187 // this.inputEl().setWidth(this.adjustWidth('input', x));
10188 // this.trigger.setStyle('left', x+'px');
10193 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10196 getResizeEl : function(){
10197 return this.inputEl();
10201 getPositionEl : function(){
10202 return this.inputEl();
10206 alignErrorIcon : function(){
10207 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10211 initEvents : function(){
10215 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10216 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10217 if(!this.multiple && this.showToggleBtn){
10218 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10219 if(this.hideTrigger){
10220 this.trigger.setDisplayed(false);
10222 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10226 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10229 if(this.removable && !this.editable && !this.tickable){
10230 var close = this.closeTriggerEl();
10233 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10234 close.on('click', this.removeBtnClick, this, close);
10238 //this.trigger.addClassOnOver('x-form-trigger-over');
10239 //this.trigger.addClassOnClick('x-form-trigger-click');
10242 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10246 closeTriggerEl : function()
10248 var close = this.el.select('.roo-combo-removable-btn', true).first();
10249 return close ? close : false;
10252 removeBtnClick : function(e, h, el)
10254 e.preventDefault();
10256 if(this.fireEvent("remove", this) !== false){
10258 this.fireEvent("afterremove", this)
10262 createList : function()
10264 this.list = Roo.get(document.body).createChild({
10266 cls: 'typeahead typeahead-long dropdown-menu',
10267 style: 'display:none'
10270 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10275 initTrigger : function(){
10280 onDestroy : function(){
10282 this.trigger.removeAllListeners();
10283 // this.trigger.remove();
10286 // this.wrap.remove();
10288 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10292 onFocus : function(){
10293 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10295 if(!this.mimicing){
10296 this.wrap.addClass('x-trigger-wrap-focus');
10297 this.mimicing = true;
10298 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10299 if(this.monitorTab){
10300 this.el.on("keydown", this.checkTab, this);
10307 checkTab : function(e){
10308 if(e.getKey() == e.TAB){
10309 this.triggerBlur();
10314 onBlur : function(){
10319 mimicBlur : function(e, t){
10321 if(!this.wrap.contains(t) && this.validateBlur()){
10322 this.triggerBlur();
10328 triggerBlur : function(){
10329 this.mimicing = false;
10330 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10331 if(this.monitorTab){
10332 this.el.un("keydown", this.checkTab, this);
10334 //this.wrap.removeClass('x-trigger-wrap-focus');
10335 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10339 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10340 validateBlur : function(e, t){
10345 onDisable : function(){
10346 this.inputEl().dom.disabled = true;
10347 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10349 // this.wrap.addClass('x-item-disabled');
10354 onEnable : function(){
10355 this.inputEl().dom.disabled = false;
10356 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10358 // this.el.removeClass('x-item-disabled');
10363 onShow : function(){
10364 var ae = this.getActionEl();
10367 ae.dom.style.display = '';
10368 ae.dom.style.visibility = 'visible';
10374 onHide : function(){
10375 var ae = this.getActionEl();
10376 ae.dom.style.display = 'none';
10380 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10381 * by an implementing function.
10383 * @param {EventObject} e
10385 onTriggerClick : Roo.emptyFn
10389 * Ext JS Library 1.1.1
10390 * Copyright(c) 2006-2007, Ext JS, LLC.
10392 * Originally Released Under LGPL - original licence link has changed is not relivant.
10395 * <script type="text/javascript">
10400 * @class Roo.data.SortTypes
10402 * Defines the default sorting (casting?) comparison functions used when sorting data.
10404 Roo.data.SortTypes = {
10406 * Default sort that does nothing
10407 * @param {Mixed} s The value being converted
10408 * @return {Mixed} The comparison value
10410 none : function(s){
10415 * The regular expression used to strip tags
10419 stripTagsRE : /<\/?[^>]+>/gi,
10422 * Strips all HTML tags to sort on text only
10423 * @param {Mixed} s The value being converted
10424 * @return {String} The comparison value
10426 asText : function(s){
10427 return String(s).replace(this.stripTagsRE, "");
10431 * Strips all HTML tags to sort on text only - Case insensitive
10432 * @param {Mixed} s The value being converted
10433 * @return {String} The comparison value
10435 asUCText : function(s){
10436 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10440 * Case insensitive string
10441 * @param {Mixed} s The value being converted
10442 * @return {String} The comparison value
10444 asUCString : function(s) {
10445 return String(s).toUpperCase();
10450 * @param {Mixed} s The value being converted
10451 * @return {Number} The comparison value
10453 asDate : function(s) {
10457 if(s instanceof Date){
10458 return s.getTime();
10460 return Date.parse(String(s));
10465 * @param {Mixed} s The value being converted
10466 * @return {Float} The comparison value
10468 asFloat : function(s) {
10469 var val = parseFloat(String(s).replace(/,/g, ""));
10478 * @param {Mixed} s The value being converted
10479 * @return {Number} The comparison value
10481 asInt : function(s) {
10482 var val = parseInt(String(s).replace(/,/g, ""));
10490 * Ext JS Library 1.1.1
10491 * Copyright(c) 2006-2007, Ext JS, LLC.
10493 * Originally Released Under LGPL - original licence link has changed is not relivant.
10496 * <script type="text/javascript">
10500 * @class Roo.data.Record
10501 * Instances of this class encapsulate both record <em>definition</em> information, and record
10502 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10503 * to access Records cached in an {@link Roo.data.Store} object.<br>
10505 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10506 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10509 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10511 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10512 * {@link #create}. The parameters are the same.
10513 * @param {Array} data An associative Array of data values keyed by the field name.
10514 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10515 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10516 * not specified an integer id is generated.
10518 Roo.data.Record = function(data, id){
10519 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10524 * Generate a constructor for a specific record layout.
10525 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10526 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10527 * Each field definition object may contain the following properties: <ul>
10528 * <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,
10529 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10530 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10531 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10532 * is being used, then this is a string containing the javascript expression to reference the data relative to
10533 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10534 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10535 * this may be omitted.</p></li>
10536 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10537 * <ul><li>auto (Default, implies no conversion)</li>
10542 * <li>date</li></ul></p></li>
10543 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10544 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10545 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10546 * by the Reader into an object that will be stored in the Record. It is passed the
10547 * following parameters:<ul>
10548 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10550 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10552 * <br>usage:<br><pre><code>
10553 var TopicRecord = Roo.data.Record.create(
10554 {name: 'title', mapping: 'topic_title'},
10555 {name: 'author', mapping: 'username'},
10556 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10557 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10558 {name: 'lastPoster', mapping: 'user2'},
10559 {name: 'excerpt', mapping: 'post_text'}
10562 var myNewRecord = new TopicRecord({
10563 title: 'Do my job please',
10566 lastPost: new Date(),
10567 lastPoster: 'Animal',
10568 excerpt: 'No way dude!'
10570 myStore.add(myNewRecord);
10575 Roo.data.Record.create = function(o){
10576 var f = function(){
10577 f.superclass.constructor.apply(this, arguments);
10579 Roo.extend(f, Roo.data.Record);
10580 var p = f.prototype;
10581 p.fields = new Roo.util.MixedCollection(false, function(field){
10584 for(var i = 0, len = o.length; i < len; i++){
10585 p.fields.add(new Roo.data.Field(o[i]));
10587 f.getField = function(name){
10588 return p.fields.get(name);
10593 Roo.data.Record.AUTO_ID = 1000;
10594 Roo.data.Record.EDIT = 'edit';
10595 Roo.data.Record.REJECT = 'reject';
10596 Roo.data.Record.COMMIT = 'commit';
10598 Roo.data.Record.prototype = {
10600 * Readonly flag - true if this record has been modified.
10609 join : function(store){
10610 this.store = store;
10614 * Set the named field to the specified value.
10615 * @param {String} name The name of the field to set.
10616 * @param {Object} value The value to set the field to.
10618 set : function(name, value){
10619 if(this.data[name] == value){
10623 if(!this.modified){
10624 this.modified = {};
10626 if(typeof this.modified[name] == 'undefined'){
10627 this.modified[name] = this.data[name];
10629 this.data[name] = value;
10630 if(!this.editing && this.store){
10631 this.store.afterEdit(this);
10636 * Get the value of the named field.
10637 * @param {String} name The name of the field to get the value of.
10638 * @return {Object} The value of the field.
10640 get : function(name){
10641 return this.data[name];
10645 beginEdit : function(){
10646 this.editing = true;
10647 this.modified = {};
10651 cancelEdit : function(){
10652 this.editing = false;
10653 delete this.modified;
10657 endEdit : function(){
10658 this.editing = false;
10659 if(this.dirty && this.store){
10660 this.store.afterEdit(this);
10665 * Usually called by the {@link Roo.data.Store} which owns the Record.
10666 * Rejects all changes made to the Record since either creation, or the last commit operation.
10667 * Modified fields are reverted to their original values.
10669 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10670 * of reject operations.
10672 reject : function(){
10673 var m = this.modified;
10675 if(typeof m[n] != "function"){
10676 this.data[n] = m[n];
10679 this.dirty = false;
10680 delete this.modified;
10681 this.editing = false;
10683 this.store.afterReject(this);
10688 * Usually called by the {@link Roo.data.Store} which owns the Record.
10689 * Commits all changes made to the Record since either creation, or the last commit operation.
10691 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10692 * of commit operations.
10694 commit : function(){
10695 this.dirty = false;
10696 delete this.modified;
10697 this.editing = false;
10699 this.store.afterCommit(this);
10704 hasError : function(){
10705 return this.error != null;
10709 clearError : function(){
10714 * Creates a copy of this record.
10715 * @param {String} id (optional) A new record id if you don't want to use this record's id
10718 copy : function(newId) {
10719 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10723 * Ext JS Library 1.1.1
10724 * Copyright(c) 2006-2007, Ext JS, LLC.
10726 * Originally Released Under LGPL - original licence link has changed is not relivant.
10729 * <script type="text/javascript">
10735 * @class Roo.data.Store
10736 * @extends Roo.util.Observable
10737 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10738 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10740 * 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
10741 * has no knowledge of the format of the data returned by the Proxy.<br>
10743 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10744 * instances from the data object. These records are cached and made available through accessor functions.
10746 * Creates a new Store.
10747 * @param {Object} config A config object containing the objects needed for the Store to access data,
10748 * and read the data into Records.
10750 Roo.data.Store = function(config){
10751 this.data = new Roo.util.MixedCollection(false);
10752 this.data.getKey = function(o){
10755 this.baseParams = {};
10757 this.paramNames = {
10762 "multisort" : "_multisort"
10765 if(config && config.data){
10766 this.inlineData = config.data;
10767 delete config.data;
10770 Roo.apply(this, config);
10772 if(this.reader){ // reader passed
10773 this.reader = Roo.factory(this.reader, Roo.data);
10774 this.reader.xmodule = this.xmodule || false;
10775 if(!this.recordType){
10776 this.recordType = this.reader.recordType;
10778 if(this.reader.onMetaChange){
10779 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10783 if(this.recordType){
10784 this.fields = this.recordType.prototype.fields;
10786 this.modified = [];
10790 * @event datachanged
10791 * Fires when the data cache has changed, and a widget which is using this Store
10792 * as a Record cache should refresh its view.
10793 * @param {Store} this
10795 datachanged : true,
10797 * @event metachange
10798 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10799 * @param {Store} this
10800 * @param {Object} meta The JSON metadata
10805 * Fires when Records have been added to the Store
10806 * @param {Store} this
10807 * @param {Roo.data.Record[]} records The array of Records added
10808 * @param {Number} index The index at which the record(s) were added
10813 * Fires when a Record has been removed from the Store
10814 * @param {Store} this
10815 * @param {Roo.data.Record} record The Record that was removed
10816 * @param {Number} index The index at which the record was removed
10821 * Fires when a Record has been updated
10822 * @param {Store} this
10823 * @param {Roo.data.Record} record The Record that was updated
10824 * @param {String} operation The update operation being performed. Value may be one of:
10826 Roo.data.Record.EDIT
10827 Roo.data.Record.REJECT
10828 Roo.data.Record.COMMIT
10834 * Fires when the data cache has been cleared.
10835 * @param {Store} this
10839 * @event beforeload
10840 * Fires before a request is made for a new data object. If the beforeload handler returns false
10841 * the load action will be canceled.
10842 * @param {Store} this
10843 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10847 * @event beforeloadadd
10848 * Fires after a new set of Records has been loaded.
10849 * @param {Store} this
10850 * @param {Roo.data.Record[]} records The Records that were loaded
10851 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10853 beforeloadadd : true,
10856 * Fires after a new set of Records has been loaded, before they are added to the store.
10857 * @param {Store} this
10858 * @param {Roo.data.Record[]} records The Records that were loaded
10859 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10860 * @params {Object} return from reader
10864 * @event loadexception
10865 * Fires if an exception occurs in the Proxy during loading.
10866 * Called with the signature of the Proxy's "loadexception" event.
10867 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10870 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10871 * @param {Object} load options
10872 * @param {Object} jsonData from your request (normally this contains the Exception)
10874 loadexception : true
10878 this.proxy = Roo.factory(this.proxy, Roo.data);
10879 this.proxy.xmodule = this.xmodule || false;
10880 this.relayEvents(this.proxy, ["loadexception"]);
10882 this.sortToggle = {};
10883 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10885 Roo.data.Store.superclass.constructor.call(this);
10887 if(this.inlineData){
10888 this.loadData(this.inlineData);
10889 delete this.inlineData;
10893 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10895 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10896 * without a remote query - used by combo/forms at present.
10900 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10903 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10906 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10907 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10910 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10911 * on any HTTP request
10914 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10917 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10921 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10922 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10924 remoteSort : false,
10927 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10928 * loaded or when a record is removed. (defaults to false).
10930 pruneModifiedRecords : false,
10933 lastOptions : null,
10936 * Add Records to the Store and fires the add event.
10937 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10939 add : function(records){
10940 records = [].concat(records);
10941 for(var i = 0, len = records.length; i < len; i++){
10942 records[i].join(this);
10944 var index = this.data.length;
10945 this.data.addAll(records);
10946 this.fireEvent("add", this, records, index);
10950 * Remove a Record from the Store and fires the remove event.
10951 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10953 remove : function(record){
10954 var index = this.data.indexOf(record);
10955 this.data.removeAt(index);
10956 if(this.pruneModifiedRecords){
10957 this.modified.remove(record);
10959 this.fireEvent("remove", this, record, index);
10963 * Remove all Records from the Store and fires the clear event.
10965 removeAll : function(){
10967 if(this.pruneModifiedRecords){
10968 this.modified = [];
10970 this.fireEvent("clear", this);
10974 * Inserts Records to the Store at the given index and fires the add event.
10975 * @param {Number} index The start index at which to insert the passed Records.
10976 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10978 insert : function(index, records){
10979 records = [].concat(records);
10980 for(var i = 0, len = records.length; i < len; i++){
10981 this.data.insert(index, records[i]);
10982 records[i].join(this);
10984 this.fireEvent("add", this, records, index);
10988 * Get the index within the cache of the passed Record.
10989 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10990 * @return {Number} The index of the passed Record. Returns -1 if not found.
10992 indexOf : function(record){
10993 return this.data.indexOf(record);
10997 * Get the index within the cache of the Record with the passed id.
10998 * @param {String} id The id of the Record to find.
10999 * @return {Number} The index of the Record. Returns -1 if not found.
11001 indexOfId : function(id){
11002 return this.data.indexOfKey(id);
11006 * Get the Record with the specified id.
11007 * @param {String} id The id of the Record to find.
11008 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11010 getById : function(id){
11011 return this.data.key(id);
11015 * Get the Record at the specified index.
11016 * @param {Number} index The index of the Record to find.
11017 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11019 getAt : function(index){
11020 return this.data.itemAt(index);
11024 * Returns a range of Records between specified indices.
11025 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11026 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11027 * @return {Roo.data.Record[]} An array of Records
11029 getRange : function(start, end){
11030 return this.data.getRange(start, end);
11034 storeOptions : function(o){
11035 o = Roo.apply({}, o);
11038 this.lastOptions = o;
11042 * Loads the Record cache from the configured Proxy using the configured Reader.
11044 * If using remote paging, then the first load call must specify the <em>start</em>
11045 * and <em>limit</em> properties in the options.params property to establish the initial
11046 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11048 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11049 * and this call will return before the new data has been loaded. Perform any post-processing
11050 * in a callback function, or in a "load" event handler.</strong>
11052 * @param {Object} options An object containing properties which control loading options:<ul>
11053 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11054 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11055 * passed the following arguments:<ul>
11056 * <li>r : Roo.data.Record[]</li>
11057 * <li>options: Options object from the load call</li>
11058 * <li>success: Boolean success indicator</li></ul></li>
11059 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11060 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11063 load : function(options){
11064 options = options || {};
11065 if(this.fireEvent("beforeload", this, options) !== false){
11066 this.storeOptions(options);
11067 var p = Roo.apply(options.params || {}, this.baseParams);
11068 // if meta was not loaded from remote source.. try requesting it.
11069 if (!this.reader.metaFromRemote) {
11070 p._requestMeta = 1;
11072 if(this.sortInfo && this.remoteSort){
11073 var pn = this.paramNames;
11074 p[pn["sort"]] = this.sortInfo.field;
11075 p[pn["dir"]] = this.sortInfo.direction;
11077 if (this.multiSort) {
11078 var pn = this.paramNames;
11079 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11082 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11087 * Reloads the Record cache from the configured Proxy using the configured Reader and
11088 * the options from the last load operation performed.
11089 * @param {Object} options (optional) An object containing properties which may override the options
11090 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11091 * the most recently used options are reused).
11093 reload : function(options){
11094 this.load(Roo.applyIf(options||{}, this.lastOptions));
11098 // Called as a callback by the Reader during a load operation.
11099 loadRecords : function(o, options, success){
11100 if(!o || success === false){
11101 if(success !== false){
11102 this.fireEvent("load", this, [], options, o);
11104 if(options.callback){
11105 options.callback.call(options.scope || this, [], options, false);
11109 // if data returned failure - throw an exception.
11110 if (o.success === false) {
11111 // show a message if no listener is registered.
11112 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11113 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11115 // loadmask wil be hooked into this..
11116 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11119 var r = o.records, t = o.totalRecords || r.length;
11121 this.fireEvent("beforeloadadd", this, r, options, o);
11123 if(!options || options.add !== true){
11124 if(this.pruneModifiedRecords){
11125 this.modified = [];
11127 for(var i = 0, len = r.length; i < len; i++){
11131 this.data = this.snapshot;
11132 delete this.snapshot;
11135 this.data.addAll(r);
11136 this.totalLength = t;
11138 this.fireEvent("datachanged", this);
11140 this.totalLength = Math.max(t, this.data.length+r.length);
11144 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11146 var e = new Roo.data.Record({});
11148 e.set(this.parent.displayField, this.parent.emptyTitle);
11149 e.set(this.parent.valueField, '');
11154 this.fireEvent("load", this, r, options, o);
11155 if(options.callback){
11156 options.callback.call(options.scope || this, r, options, true);
11162 * Loads data from a passed data block. A Reader which understands the format of the data
11163 * must have been configured in the constructor.
11164 * @param {Object} data The data block from which to read the Records. The format of the data expected
11165 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11166 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11168 loadData : function(o, append){
11169 var r = this.reader.readRecords(o);
11170 this.loadRecords(r, {add: append}, true);
11174 * Gets the number of cached records.
11176 * <em>If using paging, this may not be the total size of the dataset. If the data object
11177 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11178 * the data set size</em>
11180 getCount : function(){
11181 return this.data.length || 0;
11185 * Gets the total number of records in the dataset as returned by the server.
11187 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11188 * the dataset size</em>
11190 getTotalCount : function(){
11191 return this.totalLength || 0;
11195 * Returns the sort state of the Store as an object with two properties:
11197 field {String} The name of the field by which the Records are sorted
11198 direction {String} The sort order, "ASC" or "DESC"
11201 getSortState : function(){
11202 return this.sortInfo;
11206 applySort : function(){
11207 if(this.sortInfo && !this.remoteSort){
11208 var s = this.sortInfo, f = s.field;
11209 var st = this.fields.get(f).sortType;
11210 var fn = function(r1, r2){
11211 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11212 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11214 this.data.sort(s.direction, fn);
11215 if(this.snapshot && this.snapshot != this.data){
11216 this.snapshot.sort(s.direction, fn);
11222 * Sets the default sort column and order to be used by the next load operation.
11223 * @param {String} fieldName The name of the field to sort by.
11224 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11226 setDefaultSort : function(field, dir){
11227 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11231 * Sort the Records.
11232 * If remote sorting is used, the sort is performed on the server, and the cache is
11233 * reloaded. If local sorting is used, the cache is sorted internally.
11234 * @param {String} fieldName The name of the field to sort by.
11235 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11237 sort : function(fieldName, dir){
11238 var f = this.fields.get(fieldName);
11240 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11242 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11243 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11248 this.sortToggle[f.name] = dir;
11249 this.sortInfo = {field: f.name, direction: dir};
11250 if(!this.remoteSort){
11252 this.fireEvent("datachanged", this);
11254 this.load(this.lastOptions);
11259 * Calls the specified function for each of the Records in the cache.
11260 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11261 * Returning <em>false</em> aborts and exits the iteration.
11262 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11264 each : function(fn, scope){
11265 this.data.each(fn, scope);
11269 * Gets all records modified since the last commit. Modified records are persisted across load operations
11270 * (e.g., during paging).
11271 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11273 getModifiedRecords : function(){
11274 return this.modified;
11278 createFilterFn : function(property, value, anyMatch){
11279 if(!value.exec){ // not a regex
11280 value = String(value);
11281 if(value.length == 0){
11284 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11286 return function(r){
11287 return value.test(r.data[property]);
11292 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11293 * @param {String} property A field on your records
11294 * @param {Number} start The record index to start at (defaults to 0)
11295 * @param {Number} end The last record index to include (defaults to length - 1)
11296 * @return {Number} The sum
11298 sum : function(property, start, end){
11299 var rs = this.data.items, v = 0;
11300 start = start || 0;
11301 end = (end || end === 0) ? end : rs.length-1;
11303 for(var i = start; i <= end; i++){
11304 v += (rs[i].data[property] || 0);
11310 * Filter the records by a specified property.
11311 * @param {String} field A field on your records
11312 * @param {String/RegExp} value Either a string that the field
11313 * should start with or a RegExp to test against the field
11314 * @param {Boolean} anyMatch True to match any part not just the beginning
11316 filter : function(property, value, anyMatch){
11317 var fn = this.createFilterFn(property, value, anyMatch);
11318 return fn ? this.filterBy(fn) : this.clearFilter();
11322 * Filter by a function. The specified function will be called with each
11323 * record in this data source. If the function returns true the record is included,
11324 * otherwise it is filtered.
11325 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11326 * @param {Object} scope (optional) The scope of the function (defaults to this)
11328 filterBy : function(fn, scope){
11329 this.snapshot = this.snapshot || this.data;
11330 this.data = this.queryBy(fn, scope||this);
11331 this.fireEvent("datachanged", this);
11335 * Query the records by a specified property.
11336 * @param {String} field A field on your records
11337 * @param {String/RegExp} value Either a string that the field
11338 * should start with or a RegExp to test against the field
11339 * @param {Boolean} anyMatch True to match any part not just the beginning
11340 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11342 query : function(property, value, anyMatch){
11343 var fn = this.createFilterFn(property, value, anyMatch);
11344 return fn ? this.queryBy(fn) : this.data.clone();
11348 * Query by a function. The specified function will be called with each
11349 * record in this data source. If the function returns true the record is included
11351 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11352 * @param {Object} scope (optional) The scope of the function (defaults to this)
11353 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11355 queryBy : function(fn, scope){
11356 var data = this.snapshot || this.data;
11357 return data.filterBy(fn, scope||this);
11361 * Collects unique values for a particular dataIndex from this store.
11362 * @param {String} dataIndex The property to collect
11363 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11364 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11365 * @return {Array} An array of the unique values
11367 collect : function(dataIndex, allowNull, bypassFilter){
11368 var d = (bypassFilter === true && this.snapshot) ?
11369 this.snapshot.items : this.data.items;
11370 var v, sv, r = [], l = {};
11371 for(var i = 0, len = d.length; i < len; i++){
11372 v = d[i].data[dataIndex];
11374 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11383 * Revert to a view of the Record cache with no filtering applied.
11384 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11386 clearFilter : function(suppressEvent){
11387 if(this.snapshot && this.snapshot != this.data){
11388 this.data = this.snapshot;
11389 delete this.snapshot;
11390 if(suppressEvent !== true){
11391 this.fireEvent("datachanged", this);
11397 afterEdit : function(record){
11398 if(this.modified.indexOf(record) == -1){
11399 this.modified.push(record);
11401 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11405 afterReject : function(record){
11406 this.modified.remove(record);
11407 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11411 afterCommit : function(record){
11412 this.modified.remove(record);
11413 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11417 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11418 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11420 commitChanges : function(){
11421 var m = this.modified.slice(0);
11422 this.modified = [];
11423 for(var i = 0, len = m.length; i < len; i++){
11429 * Cancel outstanding changes on all changed records.
11431 rejectChanges : function(){
11432 var m = this.modified.slice(0);
11433 this.modified = [];
11434 for(var i = 0, len = m.length; i < len; i++){
11439 onMetaChange : function(meta, rtype, o){
11440 this.recordType = rtype;
11441 this.fields = rtype.prototype.fields;
11442 delete this.snapshot;
11443 this.sortInfo = meta.sortInfo || this.sortInfo;
11444 this.modified = [];
11445 this.fireEvent('metachange', this, this.reader.meta);
11448 moveIndex : function(data, type)
11450 var index = this.indexOf(data);
11452 var newIndex = index + type;
11456 this.insert(newIndex, data);
11461 * Ext JS Library 1.1.1
11462 * Copyright(c) 2006-2007, Ext JS, LLC.
11464 * Originally Released Under LGPL - original licence link has changed is not relivant.
11467 * <script type="text/javascript">
11471 * @class Roo.data.SimpleStore
11472 * @extends Roo.data.Store
11473 * Small helper class to make creating Stores from Array data easier.
11474 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11475 * @cfg {Array} fields An array of field definition objects, or field name strings.
11476 * @cfg {Array} data The multi-dimensional array of data
11478 * @param {Object} config
11480 Roo.data.SimpleStore = function(config){
11481 Roo.data.SimpleStore.superclass.constructor.call(this, {
11483 reader: new Roo.data.ArrayReader({
11486 Roo.data.Record.create(config.fields)
11488 proxy : new Roo.data.MemoryProxy(config.data)
11492 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11494 * Ext JS Library 1.1.1
11495 * Copyright(c) 2006-2007, Ext JS, LLC.
11497 * Originally Released Under LGPL - original licence link has changed is not relivant.
11500 * <script type="text/javascript">
11505 * @extends Roo.data.Store
11506 * @class Roo.data.JsonStore
11507 * Small helper class to make creating Stores for JSON data easier. <br/>
11509 var store = new Roo.data.JsonStore({
11510 url: 'get-images.php',
11512 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11515 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11516 * JsonReader and HttpProxy (unless inline data is provided).</b>
11517 * @cfg {Array} fields An array of field definition objects, or field name strings.
11519 * @param {Object} config
11521 Roo.data.JsonStore = function(c){
11522 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11523 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11524 reader: new Roo.data.JsonReader(c, c.fields)
11527 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11529 * Ext JS Library 1.1.1
11530 * Copyright(c) 2006-2007, Ext JS, LLC.
11532 * Originally Released Under LGPL - original licence link has changed is not relivant.
11535 * <script type="text/javascript">
11539 Roo.data.Field = function(config){
11540 if(typeof config == "string"){
11541 config = {name: config};
11543 Roo.apply(this, config);
11546 this.type = "auto";
11549 var st = Roo.data.SortTypes;
11550 // named sortTypes are supported, here we look them up
11551 if(typeof this.sortType == "string"){
11552 this.sortType = st[this.sortType];
11555 // set default sortType for strings and dates
11556 if(!this.sortType){
11559 this.sortType = st.asUCString;
11562 this.sortType = st.asDate;
11565 this.sortType = st.none;
11570 var stripRe = /[\$,%]/g;
11572 // prebuilt conversion function for this field, instead of
11573 // switching every time we're reading a value
11575 var cv, dateFormat = this.dateFormat;
11580 cv = function(v){ return v; };
11583 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11587 return v !== undefined && v !== null && v !== '' ?
11588 parseInt(String(v).replace(stripRe, ""), 10) : '';
11593 return v !== undefined && v !== null && v !== '' ?
11594 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11599 cv = function(v){ return v === true || v === "true" || v == 1; };
11606 if(v instanceof Date){
11610 if(dateFormat == "timestamp"){
11611 return new Date(v*1000);
11613 return Date.parseDate(v, dateFormat);
11615 var parsed = Date.parse(v);
11616 return parsed ? new Date(parsed) : null;
11625 Roo.data.Field.prototype = {
11633 * Ext JS Library 1.1.1
11634 * Copyright(c) 2006-2007, Ext JS, LLC.
11636 * Originally Released Under LGPL - original licence link has changed is not relivant.
11639 * <script type="text/javascript">
11642 // Base class for reading structured data from a data source. This class is intended to be
11643 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11646 * @class Roo.data.DataReader
11647 * Base class for reading structured data from a data source. This class is intended to be
11648 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11651 Roo.data.DataReader = function(meta, recordType){
11655 this.recordType = recordType instanceof Array ?
11656 Roo.data.Record.create(recordType) : recordType;
11659 Roo.data.DataReader.prototype = {
11661 * Create an empty record
11662 * @param {Object} data (optional) - overlay some values
11663 * @return {Roo.data.Record} record created.
11665 newRow : function(d) {
11667 this.recordType.prototype.fields.each(function(c) {
11669 case 'int' : da[c.name] = 0; break;
11670 case 'date' : da[c.name] = new Date(); break;
11671 case 'float' : da[c.name] = 0.0; break;
11672 case 'boolean' : da[c.name] = false; break;
11673 default : da[c.name] = ""; break;
11677 return new this.recordType(Roo.apply(da, d));
11682 * Ext JS Library 1.1.1
11683 * Copyright(c) 2006-2007, Ext JS, LLC.
11685 * Originally Released Under LGPL - original licence link has changed is not relivant.
11688 * <script type="text/javascript">
11692 * @class Roo.data.DataProxy
11693 * @extends Roo.data.Observable
11694 * This class is an abstract base class for implementations which provide retrieval of
11695 * unformatted data objects.<br>
11697 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11698 * (of the appropriate type which knows how to parse the data object) to provide a block of
11699 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11701 * Custom implementations must implement the load method as described in
11702 * {@link Roo.data.HttpProxy#load}.
11704 Roo.data.DataProxy = function(){
11707 * @event beforeload
11708 * Fires before a network request is made to retrieve a data object.
11709 * @param {Object} This DataProxy object.
11710 * @param {Object} params The params parameter to the load function.
11715 * Fires before the load method's callback is called.
11716 * @param {Object} This DataProxy object.
11717 * @param {Object} o The data object.
11718 * @param {Object} arg The callback argument object passed to the load function.
11722 * @event loadexception
11723 * Fires if an Exception occurs during data retrieval.
11724 * @param {Object} This DataProxy object.
11725 * @param {Object} o The data object.
11726 * @param {Object} arg The callback argument object passed to the load function.
11727 * @param {Object} e The Exception.
11729 loadexception : true
11731 Roo.data.DataProxy.superclass.constructor.call(this);
11734 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11737 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11741 * Ext JS Library 1.1.1
11742 * Copyright(c) 2006-2007, Ext JS, LLC.
11744 * Originally Released Under LGPL - original licence link has changed is not relivant.
11747 * <script type="text/javascript">
11750 * @class Roo.data.MemoryProxy
11751 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11752 * to the Reader when its load method is called.
11754 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11756 Roo.data.MemoryProxy = function(data){
11760 Roo.data.MemoryProxy.superclass.constructor.call(this);
11764 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11767 * Load data from the requested source (in this case an in-memory
11768 * data object passed to the constructor), read the data object into
11769 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11770 * process that block using the passed callback.
11771 * @param {Object} params This parameter is not used by the MemoryProxy class.
11772 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11773 * object into a block of Roo.data.Records.
11774 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11775 * The function must be passed <ul>
11776 * <li>The Record block object</li>
11777 * <li>The "arg" argument from the load function</li>
11778 * <li>A boolean success indicator</li>
11780 * @param {Object} scope The scope in which to call the callback
11781 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11783 load : function(params, reader, callback, scope, arg){
11784 params = params || {};
11787 result = reader.readRecords(this.data);
11789 this.fireEvent("loadexception", this, arg, null, e);
11790 callback.call(scope, null, arg, false);
11793 callback.call(scope, result, arg, true);
11797 update : function(params, records){
11802 * Ext JS Library 1.1.1
11803 * Copyright(c) 2006-2007, Ext JS, LLC.
11805 * Originally Released Under LGPL - original licence link has changed is not relivant.
11808 * <script type="text/javascript">
11811 * @class Roo.data.HttpProxy
11812 * @extends Roo.data.DataProxy
11813 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11814 * configured to reference a certain URL.<br><br>
11816 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11817 * from which the running page was served.<br><br>
11819 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11821 * Be aware that to enable the browser to parse an XML document, the server must set
11822 * the Content-Type header in the HTTP response to "text/xml".
11824 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11825 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11826 * will be used to make the request.
11828 Roo.data.HttpProxy = function(conn){
11829 Roo.data.HttpProxy.superclass.constructor.call(this);
11830 // is conn a conn config or a real conn?
11832 this.useAjax = !conn || !conn.events;
11836 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11837 // thse are take from connection...
11840 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11843 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11844 * extra parameters to each request made by this object. (defaults to undefined)
11847 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11848 * to each request made by this object. (defaults to undefined)
11851 * @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)
11854 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11857 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11863 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11867 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11868 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11869 * a finer-grained basis than the DataProxy events.
11871 getConnection : function(){
11872 return this.useAjax ? Roo.Ajax : this.conn;
11876 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11877 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11878 * process that block using the passed callback.
11879 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11880 * for the request to the remote server.
11881 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11882 * object into a block of Roo.data.Records.
11883 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11884 * The function must be passed <ul>
11885 * <li>The Record block object</li>
11886 * <li>The "arg" argument from the load function</li>
11887 * <li>A boolean success indicator</li>
11889 * @param {Object} scope The scope in which to call the callback
11890 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11892 load : function(params, reader, callback, scope, arg){
11893 if(this.fireEvent("beforeload", this, params) !== false){
11895 params : params || {},
11897 callback : callback,
11902 callback : this.loadResponse,
11906 Roo.applyIf(o, this.conn);
11907 if(this.activeRequest){
11908 Roo.Ajax.abort(this.activeRequest);
11910 this.activeRequest = Roo.Ajax.request(o);
11912 this.conn.request(o);
11915 callback.call(scope||this, null, arg, false);
11920 loadResponse : function(o, success, response){
11921 delete this.activeRequest;
11923 this.fireEvent("loadexception", this, o, response);
11924 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11929 result = o.reader.read(response);
11931 this.fireEvent("loadexception", this, o, response, e);
11932 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11936 this.fireEvent("load", this, o, o.request.arg);
11937 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11941 update : function(dataSet){
11946 updateResponse : function(dataSet){
11951 * Ext JS Library 1.1.1
11952 * Copyright(c) 2006-2007, Ext JS, LLC.
11954 * Originally Released Under LGPL - original licence link has changed is not relivant.
11957 * <script type="text/javascript">
11961 * @class Roo.data.ScriptTagProxy
11962 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11963 * other than the originating domain of the running page.<br><br>
11965 * <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
11966 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11968 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11969 * source code that is used as the source inside a <script> tag.<br><br>
11971 * In order for the browser to process the returned data, the server must wrap the data object
11972 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11973 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11974 * depending on whether the callback name was passed:
11977 boolean scriptTag = false;
11978 String cb = request.getParameter("callback");
11981 response.setContentType("text/javascript");
11983 response.setContentType("application/x-json");
11985 Writer out = response.getWriter();
11987 out.write(cb + "(");
11989 out.print(dataBlock.toJsonString());
11996 * @param {Object} config A configuration object.
11998 Roo.data.ScriptTagProxy = function(config){
11999 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12000 Roo.apply(this, config);
12001 this.head = document.getElementsByTagName("head")[0];
12004 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12006 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12008 * @cfg {String} url The URL from which to request the data object.
12011 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12015 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12016 * the server the name of the callback function set up by the load call to process the returned data object.
12017 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12018 * javascript output which calls this named function passing the data object as its only parameter.
12020 callbackParam : "callback",
12022 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12023 * name to the request.
12028 * Load data from the configured URL, read the data object into
12029 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12030 * process that block using the passed callback.
12031 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12032 * for the request to the remote server.
12033 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12034 * object into a block of Roo.data.Records.
12035 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12036 * The function must be passed <ul>
12037 * <li>The Record block object</li>
12038 * <li>The "arg" argument from the load function</li>
12039 * <li>A boolean success indicator</li>
12041 * @param {Object} scope The scope in which to call the callback
12042 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12044 load : function(params, reader, callback, scope, arg){
12045 if(this.fireEvent("beforeload", this, params) !== false){
12047 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12049 var url = this.url;
12050 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12052 url += "&_dc=" + (new Date().getTime());
12054 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12057 cb : "stcCallback"+transId,
12058 scriptId : "stcScript"+transId,
12062 callback : callback,
12068 window[trans.cb] = function(o){
12069 conn.handleResponse(o, trans);
12072 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12074 if(this.autoAbort !== false){
12078 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12080 var script = document.createElement("script");
12081 script.setAttribute("src", url);
12082 script.setAttribute("type", "text/javascript");
12083 script.setAttribute("id", trans.scriptId);
12084 this.head.appendChild(script);
12086 this.trans = trans;
12088 callback.call(scope||this, null, arg, false);
12093 isLoading : function(){
12094 return this.trans ? true : false;
12098 * Abort the current server request.
12100 abort : function(){
12101 if(this.isLoading()){
12102 this.destroyTrans(this.trans);
12107 destroyTrans : function(trans, isLoaded){
12108 this.head.removeChild(document.getElementById(trans.scriptId));
12109 clearTimeout(trans.timeoutId);
12111 window[trans.cb] = undefined;
12113 delete window[trans.cb];
12116 // if hasn't been loaded, wait for load to remove it to prevent script error
12117 window[trans.cb] = function(){
12118 window[trans.cb] = undefined;
12120 delete window[trans.cb];
12127 handleResponse : function(o, trans){
12128 this.trans = false;
12129 this.destroyTrans(trans, true);
12132 result = trans.reader.readRecords(o);
12134 this.fireEvent("loadexception", this, o, trans.arg, e);
12135 trans.callback.call(trans.scope||window, null, trans.arg, false);
12138 this.fireEvent("load", this, o, trans.arg);
12139 trans.callback.call(trans.scope||window, result, trans.arg, true);
12143 handleFailure : function(trans){
12144 this.trans = false;
12145 this.destroyTrans(trans, false);
12146 this.fireEvent("loadexception", this, null, trans.arg);
12147 trans.callback.call(trans.scope||window, null, trans.arg, false);
12151 * Ext JS Library 1.1.1
12152 * Copyright(c) 2006-2007, Ext JS, LLC.
12154 * Originally Released Under LGPL - original licence link has changed is not relivant.
12157 * <script type="text/javascript">
12161 * @class Roo.data.JsonReader
12162 * @extends Roo.data.DataReader
12163 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12164 * based on mappings in a provided Roo.data.Record constructor.
12166 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12167 * in the reply previously.
12172 var RecordDef = Roo.data.Record.create([
12173 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12174 {name: 'occupation'} // This field will use "occupation" as the mapping.
12176 var myReader = new Roo.data.JsonReader({
12177 totalProperty: "results", // The property which contains the total dataset size (optional)
12178 root: "rows", // The property which contains an Array of row objects
12179 id: "id" // The property within each row object that provides an ID for the record (optional)
12183 * This would consume a JSON file like this:
12185 { 'results': 2, 'rows': [
12186 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12187 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12190 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12191 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12192 * paged from the remote server.
12193 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12194 * @cfg {String} root name of the property which contains the Array of row objects.
12195 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12196 * @cfg {Array} fields Array of field definition objects
12198 * Create a new JsonReader
12199 * @param {Object} meta Metadata configuration options
12200 * @param {Object} recordType Either an Array of field definition objects,
12201 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12203 Roo.data.JsonReader = function(meta, recordType){
12206 // set some defaults:
12207 Roo.applyIf(meta, {
12208 totalProperty: 'total',
12209 successProperty : 'success',
12214 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12216 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12219 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12220 * Used by Store query builder to append _requestMeta to params.
12223 metaFromRemote : false,
12225 * This method is only used by a DataProxy which has retrieved data from a remote server.
12226 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12227 * @return {Object} data A data block which is used by an Roo.data.Store object as
12228 * a cache of Roo.data.Records.
12230 read : function(response){
12231 var json = response.responseText;
12233 var o = /* eval:var:o */ eval("("+json+")");
12235 throw {message: "JsonReader.read: Json object not found"};
12241 this.metaFromRemote = true;
12242 this.meta = o.metaData;
12243 this.recordType = Roo.data.Record.create(o.metaData.fields);
12244 this.onMetaChange(this.meta, this.recordType, o);
12246 return this.readRecords(o);
12249 // private function a store will implement
12250 onMetaChange : function(meta, recordType, o){
12257 simpleAccess: function(obj, subsc) {
12264 getJsonAccessor: function(){
12266 return function(expr) {
12268 return(re.test(expr))
12269 ? new Function("obj", "return obj." + expr)
12274 return Roo.emptyFn;
12279 * Create a data block containing Roo.data.Records from an XML document.
12280 * @param {Object} o An object which contains an Array of row objects in the property specified
12281 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12282 * which contains the total size of the dataset.
12283 * @return {Object} data A data block which is used by an Roo.data.Store object as
12284 * a cache of Roo.data.Records.
12286 readRecords : function(o){
12288 * After any data loads, the raw JSON data is available for further custom processing.
12292 var s = this.meta, Record = this.recordType,
12293 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12295 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12297 if(s.totalProperty) {
12298 this.getTotal = this.getJsonAccessor(s.totalProperty);
12300 if(s.successProperty) {
12301 this.getSuccess = this.getJsonAccessor(s.successProperty);
12303 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12305 var g = this.getJsonAccessor(s.id);
12306 this.getId = function(rec) {
12308 return (r === undefined || r === "") ? null : r;
12311 this.getId = function(){return null;};
12314 for(var jj = 0; jj < fl; jj++){
12316 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12317 this.ef[jj] = this.getJsonAccessor(map);
12321 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12322 if(s.totalProperty){
12323 var vt = parseInt(this.getTotal(o), 10);
12328 if(s.successProperty){
12329 var vs = this.getSuccess(o);
12330 if(vs === false || vs === 'false'){
12335 for(var i = 0; i < c; i++){
12338 var id = this.getId(n);
12339 for(var j = 0; j < fl; j++){
12341 var v = this.ef[j](n);
12343 Roo.log('missing convert for ' + f.name);
12347 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12349 var record = new Record(values, id);
12351 records[i] = record;
12357 totalRecords : totalRecords
12362 * Ext JS Library 1.1.1
12363 * Copyright(c) 2006-2007, Ext JS, LLC.
12365 * Originally Released Under LGPL - original licence link has changed is not relivant.
12368 * <script type="text/javascript">
12372 * @class Roo.data.ArrayReader
12373 * @extends Roo.data.DataReader
12374 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12375 * Each element of that Array represents a row of data fields. The
12376 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12377 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12381 var RecordDef = Roo.data.Record.create([
12382 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12383 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12385 var myReader = new Roo.data.ArrayReader({
12386 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12390 * This would consume an Array like this:
12392 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12394 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12396 * Create a new JsonReader
12397 * @param {Object} meta Metadata configuration options.
12398 * @param {Object} recordType Either an Array of field definition objects
12399 * as specified to {@link Roo.data.Record#create},
12400 * or an {@link Roo.data.Record} object
12401 * created using {@link Roo.data.Record#create}.
12403 Roo.data.ArrayReader = function(meta, recordType){
12404 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12407 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12409 * Create a data block containing Roo.data.Records from an XML document.
12410 * @param {Object} o An Array of row objects which represents the dataset.
12411 * @return {Object} data A data block which is used by an Roo.data.Store object as
12412 * a cache of Roo.data.Records.
12414 readRecords : function(o){
12415 var sid = this.meta ? this.meta.id : null;
12416 var recordType = this.recordType, fields = recordType.prototype.fields;
12419 for(var i = 0; i < root.length; i++){
12422 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12423 for(var j = 0, jlen = fields.length; j < jlen; j++){
12424 var f = fields.items[j];
12425 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12426 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12428 values[f.name] = v;
12430 var record = new recordType(values, id);
12432 records[records.length] = record;
12436 totalRecords : records.length
12445 * @class Roo.bootstrap.ComboBox
12446 * @extends Roo.bootstrap.TriggerField
12447 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12448 * @cfg {Boolean} append (true|false) default false
12449 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12450 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12451 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12452 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12453 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12454 * @cfg {Boolean} animate default true
12455 * @cfg {Boolean} emptyResultText only for touch device
12456 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12457 * @cfg {String} emptyTitle default ''
12459 * Create a new ComboBox.
12460 * @param {Object} config Configuration options
12462 Roo.bootstrap.ComboBox = function(config){
12463 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12467 * Fires when the dropdown list is expanded
12468 * @param {Roo.bootstrap.ComboBox} combo This combo box
12473 * Fires when the dropdown list is collapsed
12474 * @param {Roo.bootstrap.ComboBox} combo This combo box
12478 * @event beforeselect
12479 * Fires before a list item is selected. Return false to cancel the selection.
12480 * @param {Roo.bootstrap.ComboBox} combo This combo box
12481 * @param {Roo.data.Record} record The data record returned from the underlying store
12482 * @param {Number} index The index of the selected item in the dropdown list
12484 'beforeselect' : true,
12487 * Fires when a list item is selected
12488 * @param {Roo.bootstrap.ComboBox} combo This combo box
12489 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12490 * @param {Number} index The index of the selected item in the dropdown list
12494 * @event beforequery
12495 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12496 * The event object passed has these properties:
12497 * @param {Roo.bootstrap.ComboBox} combo This combo box
12498 * @param {String} query The query
12499 * @param {Boolean} forceAll true to force "all" query
12500 * @param {Boolean} cancel true to cancel the query
12501 * @param {Object} e The query event object
12503 'beforequery': true,
12506 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12507 * @param {Roo.bootstrap.ComboBox} combo This combo box
12512 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12513 * @param {Roo.bootstrap.ComboBox} combo This combo box
12514 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12519 * Fires when the remove value from the combobox array
12520 * @param {Roo.bootstrap.ComboBox} combo This combo box
12524 * @event afterremove
12525 * Fires when the remove value from the combobox array
12526 * @param {Roo.bootstrap.ComboBox} combo This combo box
12528 'afterremove' : true,
12530 * @event specialfilter
12531 * Fires when specialfilter
12532 * @param {Roo.bootstrap.ComboBox} combo This combo box
12534 'specialfilter' : true,
12537 * Fires when tick the element
12538 * @param {Roo.bootstrap.ComboBox} combo This combo box
12542 * @event touchviewdisplay
12543 * Fires when touch view require special display (default is using displayField)
12544 * @param {Roo.bootstrap.ComboBox} combo This combo box
12545 * @param {Object} cfg set html .
12547 'touchviewdisplay' : true
12552 this.tickItems = [];
12554 this.selectedIndex = -1;
12555 if(this.mode == 'local'){
12556 if(config.queryDelay === undefined){
12557 this.queryDelay = 10;
12559 if(config.minChars === undefined){
12565 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12568 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12569 * rendering into an Roo.Editor, defaults to false)
12572 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12573 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12576 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12579 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12580 * the dropdown list (defaults to undefined, with no header element)
12584 * @cfg {String/Roo.Template} tpl The template to use to render the output
12588 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12590 listWidth: undefined,
12592 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12593 * mode = 'remote' or 'text' if mode = 'local')
12595 displayField: undefined,
12598 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12599 * mode = 'remote' or 'value' if mode = 'local').
12600 * Note: use of a valueField requires the user make a selection
12601 * in order for a value to be mapped.
12603 valueField: undefined,
12605 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12610 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12611 * field's data value (defaults to the underlying DOM element's name)
12613 hiddenName: undefined,
12615 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12619 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12621 selectedClass: 'active',
12624 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12628 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12629 * anchor positions (defaults to 'tl-bl')
12631 listAlign: 'tl-bl?',
12633 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12637 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12638 * query specified by the allQuery config option (defaults to 'query')
12640 triggerAction: 'query',
12642 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12643 * (defaults to 4, does not apply if editable = false)
12647 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12648 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12652 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12653 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12657 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12658 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12662 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12663 * when editable = true (defaults to false)
12665 selectOnFocus:false,
12667 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12669 queryParam: 'query',
12671 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12672 * when mode = 'remote' (defaults to 'Loading...')
12674 loadingText: 'Loading...',
12676 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12680 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12684 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12685 * traditional select (defaults to true)
12689 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12693 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12697 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12698 * listWidth has a higher value)
12702 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12703 * allow the user to set arbitrary text into the field (defaults to false)
12705 forceSelection:false,
12707 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12708 * if typeAhead = true (defaults to 250)
12710 typeAheadDelay : 250,
12712 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12713 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12715 valueNotFoundText : undefined,
12717 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12719 blockFocus : false,
12722 * @cfg {Boolean} disableClear Disable showing of clear button.
12724 disableClear : false,
12726 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12728 alwaysQuery : false,
12731 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12736 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12738 invalidClass : "has-warning",
12741 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12743 validClass : "has-success",
12746 * @cfg {Boolean} specialFilter (true|false) special filter default false
12748 specialFilter : false,
12751 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12753 mobileTouchView : true,
12756 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12758 useNativeIOS : false,
12760 ios_options : false,
12772 btnPosition : 'right',
12773 triggerList : true,
12774 showToggleBtn : true,
12776 emptyResultText: 'Empty',
12777 triggerText : 'Select',
12780 // element that contains real text value.. (when hidden is used..)
12782 getAutoCreate : function()
12787 * Render classic select for iso
12790 if(Roo.isIOS && this.useNativeIOS){
12791 cfg = this.getAutoCreateNativeIOS();
12799 if(Roo.isTouch && this.mobileTouchView){
12800 cfg = this.getAutoCreateTouchView();
12807 if(!this.tickable){
12808 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12813 * ComboBox with tickable selections
12816 var align = this.labelAlign || this.parentLabelAlign();
12819 cls : 'form-group roo-combobox-tickable' //input-group
12822 var btn_text_select = '';
12823 var btn_text_done = '';
12824 var btn_text_cancel = '';
12826 if (this.btn_text_show) {
12827 btn_text_select = 'Select';
12828 btn_text_done = 'Done';
12829 btn_text_cancel = 'Cancel';
12834 cls : 'tickable-buttons',
12839 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12840 //html : this.triggerText
12841 html: btn_text_select
12847 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12849 html: btn_text_done
12855 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12857 html: btn_text_cancel
12863 buttons.cn.unshift({
12865 cls: 'roo-select2-search-field-input'
12871 Roo.each(buttons.cn, function(c){
12873 c.cls += ' btn-' + _this.size;
12876 if (_this.disabled) {
12887 cls: 'form-hidden-field'
12891 cls: 'roo-select2-choices',
12895 cls: 'roo-select2-search-field',
12906 cls: 'roo-select2-container input-group roo-select2-container-multi',
12911 // cls: 'typeahead typeahead-long dropdown-menu',
12912 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12917 if(this.hasFeedback && !this.allowBlank){
12921 cls: 'glyphicon form-control-feedback'
12924 combobox.cn.push(feedback);
12928 if (align ==='left' && this.fieldLabel.length) {
12930 cfg.cls += ' roo-form-group-label-left';
12935 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12936 tooltip : 'This field is required'
12941 cls : 'control-label',
12942 html : this.fieldLabel
12954 var labelCfg = cfg.cn[1];
12955 var contentCfg = cfg.cn[2];
12958 if(this.indicatorpos == 'right'){
12964 cls : 'control-label',
12968 html : this.fieldLabel
12972 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12973 tooltip : 'This field is required'
12988 labelCfg = cfg.cn[0];
12989 contentCfg = cfg.cn[1];
12993 if(this.labelWidth > 12){
12994 labelCfg.style = "width: " + this.labelWidth + 'px';
12997 if(this.labelWidth < 13 && this.labelmd == 0){
12998 this.labelmd = this.labelWidth;
13001 if(this.labellg > 0){
13002 labelCfg.cls += ' col-lg-' + this.labellg;
13003 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13006 if(this.labelmd > 0){
13007 labelCfg.cls += ' col-md-' + this.labelmd;
13008 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13011 if(this.labelsm > 0){
13012 labelCfg.cls += ' col-sm-' + this.labelsm;
13013 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13016 if(this.labelxs > 0){
13017 labelCfg.cls += ' col-xs-' + this.labelxs;
13018 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13022 } else if ( this.fieldLabel.length) {
13023 // Roo.log(" label");
13027 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13028 tooltip : 'This field is required'
13032 //cls : 'input-group-addon',
13033 html : this.fieldLabel
13038 if(this.indicatorpos == 'right'){
13042 //cls : 'input-group-addon',
13043 html : this.fieldLabel
13047 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13048 tooltip : 'This field is required'
13057 // Roo.log(" no label && no align");
13064 ['xs','sm','md','lg'].map(function(size){
13065 if (settings[size]) {
13066 cfg.cls += ' col-' + size + '-' + settings[size];
13074 _initEventsCalled : false,
13077 initEvents: function()
13079 if (this._initEventsCalled) { // as we call render... prevent looping...
13082 this._initEventsCalled = true;
13085 throw "can not find store for combo";
13088 this.indicator = this.indicatorEl();
13090 this.store = Roo.factory(this.store, Roo.data);
13091 this.store.parent = this;
13093 // if we are building from html. then this element is so complex, that we can not really
13094 // use the rendered HTML.
13095 // so we have to trash and replace the previous code.
13096 if (Roo.XComponent.build_from_html) {
13097 // remove this element....
13098 var e = this.el.dom, k=0;
13099 while (e ) { e = e.previousSibling; ++k;}
13104 this.rendered = false;
13106 this.render(this.parent().getChildContainer(true), k);
13109 if(Roo.isIOS && this.useNativeIOS){
13110 this.initIOSView();
13118 if(Roo.isTouch && this.mobileTouchView){
13119 this.initTouchView();
13124 this.initTickableEvents();
13128 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13130 if(this.hiddenName){
13132 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13134 this.hiddenField.dom.value =
13135 this.hiddenValue !== undefined ? this.hiddenValue :
13136 this.value !== undefined ? this.value : '';
13138 // prevent input submission
13139 this.el.dom.removeAttribute('name');
13140 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13145 // this.el.dom.setAttribute('autocomplete', 'off');
13148 var cls = 'x-combo-list';
13150 //this.list = new Roo.Layer({
13151 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13157 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13158 _this.list.setWidth(lw);
13161 this.list.on('mouseover', this.onViewOver, this);
13162 this.list.on('mousemove', this.onViewMove, this);
13163 this.list.on('scroll', this.onViewScroll, this);
13166 this.list.swallowEvent('mousewheel');
13167 this.assetHeight = 0;
13170 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13171 this.assetHeight += this.header.getHeight();
13174 this.innerList = this.list.createChild({cls:cls+'-inner'});
13175 this.innerList.on('mouseover', this.onViewOver, this);
13176 this.innerList.on('mousemove', this.onViewMove, this);
13177 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13179 if(this.allowBlank && !this.pageSize && !this.disableClear){
13180 this.footer = this.list.createChild({cls:cls+'-ft'});
13181 this.pageTb = new Roo.Toolbar(this.footer);
13185 this.footer = this.list.createChild({cls:cls+'-ft'});
13186 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13187 {pageSize: this.pageSize});
13191 if (this.pageTb && this.allowBlank && !this.disableClear) {
13193 this.pageTb.add(new Roo.Toolbar.Fill(), {
13194 cls: 'x-btn-icon x-btn-clear',
13196 handler: function()
13199 _this.clearValue();
13200 _this.onSelect(false, -1);
13205 this.assetHeight += this.footer.getHeight();
13210 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13213 this.view = new Roo.View(this.list, this.tpl, {
13214 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13216 //this.view.wrapEl.setDisplayed(false);
13217 this.view.on('click', this.onViewClick, this);
13220 this.store.on('beforeload', this.onBeforeLoad, this);
13221 this.store.on('load', this.onLoad, this);
13222 this.store.on('loadexception', this.onLoadException, this);
13224 if(this.resizable){
13225 this.resizer = new Roo.Resizable(this.list, {
13226 pinned:true, handles:'se'
13228 this.resizer.on('resize', function(r, w, h){
13229 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13230 this.listWidth = w;
13231 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13232 this.restrictHeight();
13234 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13237 if(!this.editable){
13238 this.editable = true;
13239 this.setEditable(false);
13244 if (typeof(this.events.add.listeners) != 'undefined') {
13246 this.addicon = this.wrap.createChild(
13247 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13249 this.addicon.on('click', function(e) {
13250 this.fireEvent('add', this);
13253 if (typeof(this.events.edit.listeners) != 'undefined') {
13255 this.editicon = this.wrap.createChild(
13256 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13257 if (this.addicon) {
13258 this.editicon.setStyle('margin-left', '40px');
13260 this.editicon.on('click', function(e) {
13262 // we fire even if inothing is selected..
13263 this.fireEvent('edit', this, this.lastData );
13269 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13270 "up" : function(e){
13271 this.inKeyMode = true;
13275 "down" : function(e){
13276 if(!this.isExpanded()){
13277 this.onTriggerClick();
13279 this.inKeyMode = true;
13284 "enter" : function(e){
13285 // this.onViewClick();
13289 if(this.fireEvent("specialkey", this, e)){
13290 this.onViewClick(false);
13296 "esc" : function(e){
13300 "tab" : function(e){
13303 if(this.fireEvent("specialkey", this, e)){
13304 this.onViewClick(false);
13312 doRelay : function(foo, bar, hname){
13313 if(hname == 'down' || this.scope.isExpanded()){
13314 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13323 this.queryDelay = Math.max(this.queryDelay || 10,
13324 this.mode == 'local' ? 10 : 250);
13327 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13329 if(this.typeAhead){
13330 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13332 if(this.editable !== false){
13333 this.inputEl().on("keyup", this.onKeyUp, this);
13335 if(this.forceSelection){
13336 this.inputEl().on('blur', this.doForce, this);
13340 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13341 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13345 initTickableEvents: function()
13349 if(this.hiddenName){
13351 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13353 this.hiddenField.dom.value =
13354 this.hiddenValue !== undefined ? this.hiddenValue :
13355 this.value !== undefined ? this.value : '';
13357 // prevent input submission
13358 this.el.dom.removeAttribute('name');
13359 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13364 // this.list = this.el.select('ul.dropdown-menu',true).first();
13366 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13367 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13368 if(this.triggerList){
13369 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13372 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13373 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13375 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13376 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13378 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13379 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13381 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13382 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13383 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13386 this.cancelBtn.hide();
13391 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13392 _this.list.setWidth(lw);
13395 this.list.on('mouseover', this.onViewOver, this);
13396 this.list.on('mousemove', this.onViewMove, this);
13398 this.list.on('scroll', this.onViewScroll, this);
13401 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>';
13404 this.view = new Roo.View(this.list, this.tpl, {
13405 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13408 //this.view.wrapEl.setDisplayed(false);
13409 this.view.on('click', this.onViewClick, this);
13413 this.store.on('beforeload', this.onBeforeLoad, this);
13414 this.store.on('load', this.onLoad, this);
13415 this.store.on('loadexception', this.onLoadException, this);
13418 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13419 "up" : function(e){
13420 this.inKeyMode = true;
13424 "down" : function(e){
13425 this.inKeyMode = true;
13429 "enter" : function(e){
13430 if(this.fireEvent("specialkey", this, e)){
13431 this.onViewClick(false);
13437 "esc" : function(e){
13438 this.onTickableFooterButtonClick(e, false, false);
13441 "tab" : function(e){
13442 this.fireEvent("specialkey", this, e);
13444 this.onTickableFooterButtonClick(e, false, false);
13451 doRelay : function(e, fn, key){
13452 if(this.scope.isExpanded()){
13453 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13462 this.queryDelay = Math.max(this.queryDelay || 10,
13463 this.mode == 'local' ? 10 : 250);
13466 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13468 if(this.typeAhead){
13469 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13472 if(this.editable !== false){
13473 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13476 this.indicator = this.indicatorEl();
13478 if(this.indicator){
13479 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13480 this.indicator.hide();
13485 onDestroy : function(){
13487 this.view.setStore(null);
13488 this.view.el.removeAllListeners();
13489 this.view.el.remove();
13490 this.view.purgeListeners();
13493 this.list.dom.innerHTML = '';
13497 this.store.un('beforeload', this.onBeforeLoad, this);
13498 this.store.un('load', this.onLoad, this);
13499 this.store.un('loadexception', this.onLoadException, this);
13501 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13505 fireKey : function(e){
13506 if(e.isNavKeyPress() && !this.list.isVisible()){
13507 this.fireEvent("specialkey", this, e);
13512 onResize: function(w, h){
13513 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13515 // if(typeof w != 'number'){
13516 // // we do not handle it!?!?
13519 // var tw = this.trigger.getWidth();
13520 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13521 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13523 // this.inputEl().setWidth( this.adjustWidth('input', x));
13525 // //this.trigger.setStyle('left', x+'px');
13527 // if(this.list && this.listWidth === undefined){
13528 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13529 // this.list.setWidth(lw);
13530 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13538 * Allow or prevent the user from directly editing the field text. If false is passed,
13539 * the user will only be able to select from the items defined in the dropdown list. This method
13540 * is the runtime equivalent of setting the 'editable' config option at config time.
13541 * @param {Boolean} value True to allow the user to directly edit the field text
13543 setEditable : function(value){
13544 if(value == this.editable){
13547 this.editable = value;
13549 this.inputEl().dom.setAttribute('readOnly', true);
13550 this.inputEl().on('mousedown', this.onTriggerClick, this);
13551 this.inputEl().addClass('x-combo-noedit');
13553 this.inputEl().dom.setAttribute('readOnly', false);
13554 this.inputEl().un('mousedown', this.onTriggerClick, this);
13555 this.inputEl().removeClass('x-combo-noedit');
13561 onBeforeLoad : function(combo,opts){
13562 if(!this.hasFocus){
13566 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13568 this.restrictHeight();
13569 this.selectedIndex = -1;
13573 onLoad : function(){
13575 this.hasQuery = false;
13577 if(!this.hasFocus){
13581 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13582 this.loading.hide();
13585 if(this.store.getCount() > 0){
13588 this.restrictHeight();
13589 if(this.lastQuery == this.allQuery){
13590 if(this.editable && !this.tickable){
13591 this.inputEl().dom.select();
13595 !this.selectByValue(this.value, true) &&
13598 !this.store.lastOptions ||
13599 typeof(this.store.lastOptions.add) == 'undefined' ||
13600 this.store.lastOptions.add != true
13603 this.select(0, true);
13606 if(this.autoFocus){
13609 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13610 this.taTask.delay(this.typeAheadDelay);
13614 this.onEmptyResults();
13620 onLoadException : function()
13622 this.hasQuery = false;
13624 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13625 this.loading.hide();
13628 if(this.tickable && this.editable){
13633 // only causes errors at present
13634 //Roo.log(this.store.reader.jsonData);
13635 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13637 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13643 onTypeAhead : function(){
13644 if(this.store.getCount() > 0){
13645 var r = this.store.getAt(0);
13646 var newValue = r.data[this.displayField];
13647 var len = newValue.length;
13648 var selStart = this.getRawValue().length;
13650 if(selStart != len){
13651 this.setRawValue(newValue);
13652 this.selectText(selStart, newValue.length);
13658 onSelect : function(record, index){
13660 if(this.fireEvent('beforeselect', this, record, index) !== false){
13662 this.setFromData(index > -1 ? record.data : false);
13665 this.fireEvent('select', this, record, index);
13670 * Returns the currently selected field value or empty string if no value is set.
13671 * @return {String} value The selected value
13673 getValue : function()
13675 if(Roo.isIOS && this.useNativeIOS){
13676 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13680 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13683 if(this.valueField){
13684 return typeof this.value != 'undefined' ? this.value : '';
13686 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13690 getRawValue : function()
13692 if(Roo.isIOS && this.useNativeIOS){
13693 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13696 var v = this.inputEl().getValue();
13702 * Clears any text/value currently set in the field
13704 clearValue : function(){
13706 if(this.hiddenField){
13707 this.hiddenField.dom.value = '';
13710 this.setRawValue('');
13711 this.lastSelectionText = '';
13712 this.lastData = false;
13714 var close = this.closeTriggerEl();
13725 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13726 * will be displayed in the field. If the value does not match the data value of an existing item,
13727 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13728 * Otherwise the field will be blank (although the value will still be set).
13729 * @param {String} value The value to match
13731 setValue : function(v)
13733 if(Roo.isIOS && this.useNativeIOS){
13734 this.setIOSValue(v);
13744 if(this.valueField){
13745 var r = this.findRecord(this.valueField, v);
13747 text = r.data[this.displayField];
13748 }else if(this.valueNotFoundText !== undefined){
13749 text = this.valueNotFoundText;
13752 this.lastSelectionText = text;
13753 if(this.hiddenField){
13754 this.hiddenField.dom.value = v;
13756 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13759 var close = this.closeTriggerEl();
13762 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13768 * @property {Object} the last set data for the element
13773 * Sets the value of the field based on a object which is related to the record format for the store.
13774 * @param {Object} value the value to set as. or false on reset?
13776 setFromData : function(o){
13783 var dv = ''; // display value
13784 var vv = ''; // value value..
13786 if (this.displayField) {
13787 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13789 // this is an error condition!!!
13790 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13793 if(this.valueField){
13794 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13797 var close = this.closeTriggerEl();
13800 if(dv.length || vv * 1 > 0){
13802 this.blockFocus=true;
13808 if(this.hiddenField){
13809 this.hiddenField.dom.value = vv;
13811 this.lastSelectionText = dv;
13812 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13816 // no hidden field.. - we store the value in 'value', but still display
13817 // display field!!!!
13818 this.lastSelectionText = dv;
13819 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13826 reset : function(){
13827 // overridden so that last data is reset..
13834 this.setValue(this.originalValue);
13835 //this.clearInvalid();
13836 this.lastData = false;
13838 this.view.clearSelections();
13844 findRecord : function(prop, value){
13846 if(this.store.getCount() > 0){
13847 this.store.each(function(r){
13848 if(r.data[prop] == value){
13858 getName: function()
13860 // returns hidden if it's set..
13861 if (!this.rendered) {return ''};
13862 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13866 onViewMove : function(e, t){
13867 this.inKeyMode = false;
13871 onViewOver : function(e, t){
13872 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13875 var item = this.view.findItemFromChild(t);
13878 var index = this.view.indexOf(item);
13879 this.select(index, false);
13884 onViewClick : function(view, doFocus, el, e)
13886 var index = this.view.getSelectedIndexes()[0];
13888 var r = this.store.getAt(index);
13892 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13899 Roo.each(this.tickItems, function(v,k){
13901 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13903 _this.tickItems.splice(k, 1);
13905 if(typeof(e) == 'undefined' && view == false){
13906 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13918 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13919 this.tickItems.push(r.data);
13922 if(typeof(e) == 'undefined' && view == false){
13923 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13930 this.onSelect(r, index);
13932 if(doFocus !== false && !this.blockFocus){
13933 this.inputEl().focus();
13938 restrictHeight : function(){
13939 //this.innerList.dom.style.height = '';
13940 //var inner = this.innerList.dom;
13941 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13942 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13943 //this.list.beginUpdate();
13944 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13945 this.list.alignTo(this.inputEl(), this.listAlign);
13946 this.list.alignTo(this.inputEl(), this.listAlign);
13947 //this.list.endUpdate();
13951 onEmptyResults : function(){
13953 if(this.tickable && this.editable){
13954 this.restrictHeight();
13962 * Returns true if the dropdown list is expanded, else false.
13964 isExpanded : function(){
13965 return this.list.isVisible();
13969 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13970 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13971 * @param {String} value The data value of the item to select
13972 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13973 * selected item if it is not currently in view (defaults to true)
13974 * @return {Boolean} True if the value matched an item in the list, else false
13976 selectByValue : function(v, scrollIntoView){
13977 if(v !== undefined && v !== null){
13978 var r = this.findRecord(this.valueField || this.displayField, v);
13980 this.select(this.store.indexOf(r), scrollIntoView);
13988 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13989 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13990 * @param {Number} index The zero-based index of the list item to select
13991 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13992 * selected item if it is not currently in view (defaults to true)
13994 select : function(index, scrollIntoView){
13995 this.selectedIndex = index;
13996 this.view.select(index);
13997 if(scrollIntoView !== false){
13998 var el = this.view.getNode(index);
14000 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14003 this.list.scrollChildIntoView(el, false);
14009 selectNext : function(){
14010 var ct = this.store.getCount();
14012 if(this.selectedIndex == -1){
14014 }else if(this.selectedIndex < ct-1){
14015 this.select(this.selectedIndex+1);
14021 selectPrev : function(){
14022 var ct = this.store.getCount();
14024 if(this.selectedIndex == -1){
14026 }else if(this.selectedIndex != 0){
14027 this.select(this.selectedIndex-1);
14033 onKeyUp : function(e){
14034 if(this.editable !== false && !e.isSpecialKey()){
14035 this.lastKey = e.getKey();
14036 this.dqTask.delay(this.queryDelay);
14041 validateBlur : function(){
14042 return !this.list || !this.list.isVisible();
14046 initQuery : function(){
14048 var v = this.getRawValue();
14050 if(this.tickable && this.editable){
14051 v = this.tickableInputEl().getValue();
14058 doForce : function(){
14059 if(this.inputEl().dom.value.length > 0){
14060 this.inputEl().dom.value =
14061 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14067 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14068 * query allowing the query action to be canceled if needed.
14069 * @param {String} query The SQL query to execute
14070 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14071 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14072 * saved in the current store (defaults to false)
14074 doQuery : function(q, forceAll){
14076 if(q === undefined || q === null){
14081 forceAll: forceAll,
14085 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14090 forceAll = qe.forceAll;
14091 if(forceAll === true || (q.length >= this.minChars)){
14093 this.hasQuery = true;
14095 if(this.lastQuery != q || this.alwaysQuery){
14096 this.lastQuery = q;
14097 if(this.mode == 'local'){
14098 this.selectedIndex = -1;
14100 this.store.clearFilter();
14103 if(this.specialFilter){
14104 this.fireEvent('specialfilter', this);
14109 this.store.filter(this.displayField, q);
14112 this.store.fireEvent("datachanged", this.store);
14119 this.store.baseParams[this.queryParam] = q;
14121 var options = {params : this.getParams(q)};
14124 options.add = true;
14125 options.params.start = this.page * this.pageSize;
14128 this.store.load(options);
14131 * this code will make the page width larger, at the beginning, the list not align correctly,
14132 * we should expand the list on onLoad
14133 * so command out it
14138 this.selectedIndex = -1;
14143 this.loadNext = false;
14147 getParams : function(q){
14149 //p[this.queryParam] = q;
14153 p.limit = this.pageSize;
14159 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14161 collapse : function(){
14162 if(!this.isExpanded()){
14168 this.hasFocus = false;
14172 this.cancelBtn.hide();
14173 this.trigger.show();
14176 this.tickableInputEl().dom.value = '';
14177 this.tickableInputEl().blur();
14182 Roo.get(document).un('mousedown', this.collapseIf, this);
14183 Roo.get(document).un('mousewheel', this.collapseIf, this);
14184 if (!this.editable) {
14185 Roo.get(document).un('keydown', this.listKeyPress, this);
14187 this.fireEvent('collapse', this);
14193 collapseIf : function(e){
14194 var in_combo = e.within(this.el);
14195 var in_list = e.within(this.list);
14196 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14198 if (in_combo || in_list || is_list) {
14199 //e.stopPropagation();
14204 this.onTickableFooterButtonClick(e, false, false);
14212 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14214 expand : function(){
14216 if(this.isExpanded() || !this.hasFocus){
14220 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14221 this.list.setWidth(lw);
14227 this.restrictHeight();
14231 this.tickItems = Roo.apply([], this.item);
14234 this.cancelBtn.show();
14235 this.trigger.hide();
14238 this.tickableInputEl().focus();
14243 Roo.get(document).on('mousedown', this.collapseIf, this);
14244 Roo.get(document).on('mousewheel', this.collapseIf, this);
14245 if (!this.editable) {
14246 Roo.get(document).on('keydown', this.listKeyPress, this);
14249 this.fireEvent('expand', this);
14253 // Implements the default empty TriggerField.onTriggerClick function
14254 onTriggerClick : function(e)
14256 Roo.log('trigger click');
14258 if(this.disabled || !this.triggerList){
14263 this.loadNext = false;
14265 if(this.isExpanded()){
14267 if (!this.blockFocus) {
14268 this.inputEl().focus();
14272 this.hasFocus = true;
14273 if(this.triggerAction == 'all') {
14274 this.doQuery(this.allQuery, true);
14276 this.doQuery(this.getRawValue());
14278 if (!this.blockFocus) {
14279 this.inputEl().focus();
14284 onTickableTriggerClick : function(e)
14291 this.loadNext = false;
14292 this.hasFocus = true;
14294 if(this.triggerAction == 'all') {
14295 this.doQuery(this.allQuery, true);
14297 this.doQuery(this.getRawValue());
14301 onSearchFieldClick : function(e)
14303 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14304 this.onTickableFooterButtonClick(e, false, false);
14308 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14313 this.loadNext = false;
14314 this.hasFocus = true;
14316 if(this.triggerAction == 'all') {
14317 this.doQuery(this.allQuery, true);
14319 this.doQuery(this.getRawValue());
14323 listKeyPress : function(e)
14325 //Roo.log('listkeypress');
14326 // scroll to first matching element based on key pres..
14327 if (e.isSpecialKey()) {
14330 var k = String.fromCharCode(e.getKey()).toUpperCase();
14333 var csel = this.view.getSelectedNodes();
14334 var cselitem = false;
14336 var ix = this.view.indexOf(csel[0]);
14337 cselitem = this.store.getAt(ix);
14338 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14344 this.store.each(function(v) {
14346 // start at existing selection.
14347 if (cselitem.id == v.id) {
14353 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14354 match = this.store.indexOf(v);
14360 if (match === false) {
14361 return true; // no more action?
14364 this.view.select(match);
14365 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14366 sn.scrollIntoView(sn.dom.parentNode, false);
14369 onViewScroll : function(e, t){
14371 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){
14375 this.hasQuery = true;
14377 this.loading = this.list.select('.loading', true).first();
14379 if(this.loading === null){
14380 this.list.createChild({
14382 cls: 'loading roo-select2-more-results roo-select2-active',
14383 html: 'Loading more results...'
14386 this.loading = this.list.select('.loading', true).first();
14388 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14390 this.loading.hide();
14393 this.loading.show();
14398 this.loadNext = true;
14400 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14405 addItem : function(o)
14407 var dv = ''; // display value
14409 if (this.displayField) {
14410 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14412 // this is an error condition!!!
14413 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14420 var choice = this.choices.createChild({
14422 cls: 'roo-select2-search-choice',
14431 cls: 'roo-select2-search-choice-close fa fa-times',
14436 }, this.searchField);
14438 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14440 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14448 this.inputEl().dom.value = '';
14453 onRemoveItem : function(e, _self, o)
14455 e.preventDefault();
14457 this.lastItem = Roo.apply([], this.item);
14459 var index = this.item.indexOf(o.data) * 1;
14462 Roo.log('not this item?!');
14466 this.item.splice(index, 1);
14471 this.fireEvent('remove', this, e);
14477 syncValue : function()
14479 if(!this.item.length){
14486 Roo.each(this.item, function(i){
14487 if(_this.valueField){
14488 value.push(i[_this.valueField]);
14495 this.value = value.join(',');
14497 if(this.hiddenField){
14498 this.hiddenField.dom.value = this.value;
14501 this.store.fireEvent("datachanged", this.store);
14506 clearItem : function()
14508 if(!this.multiple){
14514 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14522 if(this.tickable && !Roo.isTouch){
14523 this.view.refresh();
14527 inputEl: function ()
14529 if(Roo.isIOS && this.useNativeIOS){
14530 return this.el.select('select.roo-ios-select', true).first();
14533 if(Roo.isTouch && this.mobileTouchView){
14534 return this.el.select('input.form-control',true).first();
14538 return this.searchField;
14541 return this.el.select('input.form-control',true).first();
14544 onTickableFooterButtonClick : function(e, btn, el)
14546 e.preventDefault();
14548 this.lastItem = Roo.apply([], this.item);
14550 if(btn && btn.name == 'cancel'){
14551 this.tickItems = Roo.apply([], this.item);
14560 Roo.each(this.tickItems, function(o){
14568 validate : function()
14570 var v = this.getRawValue();
14573 v = this.getValue();
14576 if(this.disabled || this.allowBlank || v.length){
14581 this.markInvalid();
14585 tickableInputEl : function()
14587 if(!this.tickable || !this.editable){
14588 return this.inputEl();
14591 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14595 getAutoCreateTouchView : function()
14600 cls: 'form-group' //input-group
14606 type : this.inputType,
14607 cls : 'form-control x-combo-noedit',
14608 autocomplete: 'new-password',
14609 placeholder : this.placeholder || '',
14614 input.name = this.name;
14618 input.cls += ' input-' + this.size;
14621 if (this.disabled) {
14622 input.disabled = true;
14633 inputblock.cls += ' input-group';
14635 inputblock.cn.unshift({
14637 cls : 'input-group-addon',
14642 if(this.removable && !this.multiple){
14643 inputblock.cls += ' roo-removable';
14645 inputblock.cn.push({
14648 cls : 'roo-combo-removable-btn close'
14652 if(this.hasFeedback && !this.allowBlank){
14654 inputblock.cls += ' has-feedback';
14656 inputblock.cn.push({
14658 cls: 'glyphicon form-control-feedback'
14665 inputblock.cls += (this.before) ? '' : ' input-group';
14667 inputblock.cn.push({
14669 cls : 'input-group-addon',
14680 cls: 'form-hidden-field'
14694 cls: 'form-hidden-field'
14698 cls: 'roo-select2-choices',
14702 cls: 'roo-select2-search-field',
14715 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14721 if(!this.multiple && this.showToggleBtn){
14728 if (this.caret != false) {
14731 cls: 'fa fa-' + this.caret
14738 cls : 'input-group-addon btn dropdown-toggle',
14743 cls: 'combobox-clear',
14757 combobox.cls += ' roo-select2-container-multi';
14760 var align = this.labelAlign || this.parentLabelAlign();
14762 if (align ==='left' && this.fieldLabel.length) {
14767 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14768 tooltip : 'This field is required'
14772 cls : 'control-label',
14773 html : this.fieldLabel
14784 var labelCfg = cfg.cn[1];
14785 var contentCfg = cfg.cn[2];
14788 if(this.indicatorpos == 'right'){
14793 cls : 'control-label',
14797 html : this.fieldLabel
14801 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14802 tooltip : 'This field is required'
14815 labelCfg = cfg.cn[0];
14816 contentCfg = cfg.cn[1];
14821 if(this.labelWidth > 12){
14822 labelCfg.style = "width: " + this.labelWidth + 'px';
14825 if(this.labelWidth < 13 && this.labelmd == 0){
14826 this.labelmd = this.labelWidth;
14829 if(this.labellg > 0){
14830 labelCfg.cls += ' col-lg-' + this.labellg;
14831 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14834 if(this.labelmd > 0){
14835 labelCfg.cls += ' col-md-' + this.labelmd;
14836 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14839 if(this.labelsm > 0){
14840 labelCfg.cls += ' col-sm-' + this.labelsm;
14841 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14844 if(this.labelxs > 0){
14845 labelCfg.cls += ' col-xs-' + this.labelxs;
14846 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14850 } else if ( this.fieldLabel.length) {
14854 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14855 tooltip : 'This field is required'
14859 cls : 'control-label',
14860 html : this.fieldLabel
14871 if(this.indicatorpos == 'right'){
14875 cls : 'control-label',
14876 html : this.fieldLabel,
14880 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14881 tooltip : 'This field is required'
14898 var settings = this;
14900 ['xs','sm','md','lg'].map(function(size){
14901 if (settings[size]) {
14902 cfg.cls += ' col-' + size + '-' + settings[size];
14909 initTouchView : function()
14911 this.renderTouchView();
14913 this.touchViewEl.on('scroll', function(){
14914 this.el.dom.scrollTop = 0;
14917 this.originalValue = this.getValue();
14919 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14921 this.inputEl().on("click", this.showTouchView, this);
14922 if (this.triggerEl) {
14923 this.triggerEl.on("click", this.showTouchView, this);
14927 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14928 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14930 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14932 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14933 this.store.on('load', this.onTouchViewLoad, this);
14934 this.store.on('loadexception', this.onTouchViewLoadException, this);
14936 if(this.hiddenName){
14938 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14940 this.hiddenField.dom.value =
14941 this.hiddenValue !== undefined ? this.hiddenValue :
14942 this.value !== undefined ? this.value : '';
14944 this.el.dom.removeAttribute('name');
14945 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14949 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14950 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14953 if(this.removable && !this.multiple){
14954 var close = this.closeTriggerEl();
14956 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14957 close.on('click', this.removeBtnClick, this, close);
14961 * fix the bug in Safari iOS8
14963 this.inputEl().on("focus", function(e){
14964 document.activeElement.blur();
14972 renderTouchView : function()
14974 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14975 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14977 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14978 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14980 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14981 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14982 this.touchViewBodyEl.setStyle('overflow', 'auto');
14984 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14985 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14987 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14988 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14992 showTouchView : function()
14998 this.touchViewHeaderEl.hide();
15000 if(this.modalTitle.length){
15001 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15002 this.touchViewHeaderEl.show();
15005 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15006 this.touchViewEl.show();
15008 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15010 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15011 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15013 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15015 if(this.modalTitle.length){
15016 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15019 this.touchViewBodyEl.setHeight(bodyHeight);
15023 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15025 this.touchViewEl.addClass('in');
15028 this.doTouchViewQuery();
15032 hideTouchView : function()
15034 this.touchViewEl.removeClass('in');
15038 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15040 this.touchViewEl.setStyle('display', 'none');
15045 setTouchViewValue : function()
15052 Roo.each(this.tickItems, function(o){
15057 this.hideTouchView();
15060 doTouchViewQuery : function()
15069 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15073 if(!this.alwaysQuery || this.mode == 'local'){
15074 this.onTouchViewLoad();
15081 onTouchViewBeforeLoad : function(combo,opts)
15087 onTouchViewLoad : function()
15089 if(this.store.getCount() < 1){
15090 this.onTouchViewEmptyResults();
15094 this.clearTouchView();
15096 var rawValue = this.getRawValue();
15098 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15100 this.tickItems = [];
15102 this.store.data.each(function(d, rowIndex){
15103 var row = this.touchViewListGroup.createChild(template);
15105 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15106 row.addClass(d.data.cls);
15109 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15112 html : d.data[this.displayField]
15115 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15116 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15119 row.removeClass('selected');
15120 if(!this.multiple && this.valueField &&
15121 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15124 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15125 row.addClass('selected');
15128 if(this.multiple && this.valueField &&
15129 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15133 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15134 this.tickItems.push(d.data);
15137 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15141 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15143 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15145 if(this.modalTitle.length){
15146 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15149 var listHeight = this.touchViewListGroup.getHeight();
15153 if(firstChecked && listHeight > bodyHeight){
15154 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15159 onTouchViewLoadException : function()
15161 this.hideTouchView();
15164 onTouchViewEmptyResults : function()
15166 this.clearTouchView();
15168 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15170 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15174 clearTouchView : function()
15176 this.touchViewListGroup.dom.innerHTML = '';
15179 onTouchViewClick : function(e, el, o)
15181 e.preventDefault();
15184 var rowIndex = o.rowIndex;
15186 var r = this.store.getAt(rowIndex);
15188 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15190 if(!this.multiple){
15191 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15192 c.dom.removeAttribute('checked');
15195 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15197 this.setFromData(r.data);
15199 var close = this.closeTriggerEl();
15205 this.hideTouchView();
15207 this.fireEvent('select', this, r, rowIndex);
15212 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15213 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15214 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15218 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15219 this.addItem(r.data);
15220 this.tickItems.push(r.data);
15224 getAutoCreateNativeIOS : function()
15227 cls: 'form-group' //input-group,
15232 cls : 'roo-ios-select'
15236 combobox.name = this.name;
15239 if (this.disabled) {
15240 combobox.disabled = true;
15243 var settings = this;
15245 ['xs','sm','md','lg'].map(function(size){
15246 if (settings[size]) {
15247 cfg.cls += ' col-' + size + '-' + settings[size];
15257 initIOSView : function()
15259 this.store.on('load', this.onIOSViewLoad, this);
15264 onIOSViewLoad : function()
15266 if(this.store.getCount() < 1){
15270 this.clearIOSView();
15272 if(this.allowBlank) {
15274 var default_text = '-- SELECT --';
15276 if(this.placeholder.length){
15277 default_text = this.placeholder;
15280 if(this.emptyTitle.length){
15281 default_text += ' - ' + this.emptyTitle + ' -';
15284 var opt = this.inputEl().createChild({
15287 html : default_text
15291 o[this.valueField] = 0;
15292 o[this.displayField] = default_text;
15294 this.ios_options.push({
15301 this.store.data.each(function(d, rowIndex){
15305 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15306 html = d.data[this.displayField];
15311 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15312 value = d.data[this.valueField];
15321 if(this.value == d.data[this.valueField]){
15322 option['selected'] = true;
15325 var opt = this.inputEl().createChild(option);
15327 this.ios_options.push({
15334 this.inputEl().on('change', function(){
15335 this.fireEvent('select', this);
15340 clearIOSView: function()
15342 this.inputEl().dom.innerHTML = '';
15344 this.ios_options = [];
15347 setIOSValue: function(v)
15351 if(!this.ios_options){
15355 Roo.each(this.ios_options, function(opts){
15357 opts.el.dom.removeAttribute('selected');
15359 if(opts.data[this.valueField] != v){
15363 opts.el.dom.setAttribute('selected', true);
15369 * @cfg {Boolean} grow
15373 * @cfg {Number} growMin
15377 * @cfg {Number} growMax
15386 Roo.apply(Roo.bootstrap.ComboBox, {
15390 cls: 'modal-header',
15412 cls: 'list-group-item',
15416 cls: 'roo-combobox-list-group-item-value'
15420 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15434 listItemCheckbox : {
15436 cls: 'list-group-item',
15440 cls: 'roo-combobox-list-group-item-value'
15444 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15460 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15465 cls: 'modal-footer',
15473 cls: 'col-xs-6 text-left',
15476 cls: 'btn btn-danger roo-touch-view-cancel',
15482 cls: 'col-xs-6 text-right',
15485 cls: 'btn btn-success roo-touch-view-ok',
15496 Roo.apply(Roo.bootstrap.ComboBox, {
15498 touchViewTemplate : {
15500 cls: 'modal fade roo-combobox-touch-view',
15504 cls: 'modal-dialog',
15505 style : 'position:fixed', // we have to fix position....
15509 cls: 'modal-content',
15511 Roo.bootstrap.ComboBox.header,
15512 Roo.bootstrap.ComboBox.body,
15513 Roo.bootstrap.ComboBox.footer
15522 * Ext JS Library 1.1.1
15523 * Copyright(c) 2006-2007, Ext JS, LLC.
15525 * Originally Released Under LGPL - original licence link has changed is not relivant.
15528 * <script type="text/javascript">
15533 * @extends Roo.util.Observable
15534 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15535 * This class also supports single and multi selection modes. <br>
15536 * Create a data model bound view:
15538 var store = new Roo.data.Store(...);
15540 var view = new Roo.View({
15542 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15544 singleSelect: true,
15545 selectedClass: "ydataview-selected",
15549 // listen for node click?
15550 view.on("click", function(vw, index, node, e){
15551 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15555 dataModel.load("foobar.xml");
15557 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15559 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15560 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15562 * Note: old style constructor is still suported (container, template, config)
15565 * Create a new View
15566 * @param {Object} config The config object
15569 Roo.View = function(config, depreciated_tpl, depreciated_config){
15571 this.parent = false;
15573 if (typeof(depreciated_tpl) == 'undefined') {
15574 // new way.. - universal constructor.
15575 Roo.apply(this, config);
15576 this.el = Roo.get(this.el);
15579 this.el = Roo.get(config);
15580 this.tpl = depreciated_tpl;
15581 Roo.apply(this, depreciated_config);
15583 this.wrapEl = this.el.wrap().wrap();
15584 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15587 if(typeof(this.tpl) == "string"){
15588 this.tpl = new Roo.Template(this.tpl);
15590 // support xtype ctors..
15591 this.tpl = new Roo.factory(this.tpl, Roo);
15595 this.tpl.compile();
15600 * @event beforeclick
15601 * Fires before a click is processed. Returns false to cancel the default action.
15602 * @param {Roo.View} this
15603 * @param {Number} index The index of the target node
15604 * @param {HTMLElement} node The target node
15605 * @param {Roo.EventObject} e The raw event object
15607 "beforeclick" : true,
15610 * Fires when a template node is clicked.
15611 * @param {Roo.View} this
15612 * @param {Number} index The index of the target node
15613 * @param {HTMLElement} node The target node
15614 * @param {Roo.EventObject} e The raw event object
15619 * Fires when a template node is double clicked.
15620 * @param {Roo.View} this
15621 * @param {Number} index The index of the target node
15622 * @param {HTMLElement} node The target node
15623 * @param {Roo.EventObject} e The raw event object
15627 * @event contextmenu
15628 * Fires when a template node is right clicked.
15629 * @param {Roo.View} this
15630 * @param {Number} index The index of the target node
15631 * @param {HTMLElement} node The target node
15632 * @param {Roo.EventObject} e The raw event object
15634 "contextmenu" : true,
15636 * @event selectionchange
15637 * Fires when the selected nodes change.
15638 * @param {Roo.View} this
15639 * @param {Array} selections Array of the selected nodes
15641 "selectionchange" : true,
15644 * @event beforeselect
15645 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15646 * @param {Roo.View} this
15647 * @param {HTMLElement} node The node to be selected
15648 * @param {Array} selections Array of currently selected nodes
15650 "beforeselect" : true,
15652 * @event preparedata
15653 * Fires on every row to render, to allow you to change the data.
15654 * @param {Roo.View} this
15655 * @param {Object} data to be rendered (change this)
15657 "preparedata" : true
15665 "click": this.onClick,
15666 "dblclick": this.onDblClick,
15667 "contextmenu": this.onContextMenu,
15671 this.selections = [];
15673 this.cmp = new Roo.CompositeElementLite([]);
15675 this.store = Roo.factory(this.store, Roo.data);
15676 this.setStore(this.store, true);
15679 if ( this.footer && this.footer.xtype) {
15681 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15683 this.footer.dataSource = this.store;
15684 this.footer.container = fctr;
15685 this.footer = Roo.factory(this.footer, Roo);
15686 fctr.insertFirst(this.el);
15688 // this is a bit insane - as the paging toolbar seems to detach the el..
15689 // dom.parentNode.parentNode.parentNode
15690 // they get detached?
15694 Roo.View.superclass.constructor.call(this);
15699 Roo.extend(Roo.View, Roo.util.Observable, {
15702 * @cfg {Roo.data.Store} store Data store to load data from.
15707 * @cfg {String|Roo.Element} el The container element.
15712 * @cfg {String|Roo.Template} tpl The template used by this View
15716 * @cfg {String} dataName the named area of the template to use as the data area
15717 * Works with domtemplates roo-name="name"
15721 * @cfg {String} selectedClass The css class to add to selected nodes
15723 selectedClass : "x-view-selected",
15725 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15730 * @cfg {String} text to display on mask (default Loading)
15734 * @cfg {Boolean} multiSelect Allow multiple selection
15736 multiSelect : false,
15738 * @cfg {Boolean} singleSelect Allow single selection
15740 singleSelect: false,
15743 * @cfg {Boolean} toggleSelect - selecting
15745 toggleSelect : false,
15748 * @cfg {Boolean} tickable - selecting
15753 * Returns the element this view is bound to.
15754 * @return {Roo.Element}
15756 getEl : function(){
15757 return this.wrapEl;
15763 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15765 refresh : function(){
15766 //Roo.log('refresh');
15769 // if we are using something like 'domtemplate', then
15770 // the what gets used is:
15771 // t.applySubtemplate(NAME, data, wrapping data..)
15772 // the outer template then get' applied with
15773 // the store 'extra data'
15774 // and the body get's added to the
15775 // roo-name="data" node?
15776 // <span class='roo-tpl-{name}'></span> ?????
15780 this.clearSelections();
15781 this.el.update("");
15783 var records = this.store.getRange();
15784 if(records.length < 1) {
15786 // is this valid?? = should it render a template??
15788 this.el.update(this.emptyText);
15792 if (this.dataName) {
15793 this.el.update(t.apply(this.store.meta)); //????
15794 el = this.el.child('.roo-tpl-' + this.dataName);
15797 for(var i = 0, len = records.length; i < len; i++){
15798 var data = this.prepareData(records[i].data, i, records[i]);
15799 this.fireEvent("preparedata", this, data, i, records[i]);
15801 var d = Roo.apply({}, data);
15804 Roo.apply(d, {'roo-id' : Roo.id()});
15808 Roo.each(this.parent.item, function(item){
15809 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15812 Roo.apply(d, {'roo-data-checked' : 'checked'});
15816 html[html.length] = Roo.util.Format.trim(
15818 t.applySubtemplate(this.dataName, d, this.store.meta) :
15825 el.update(html.join(""));
15826 this.nodes = el.dom.childNodes;
15827 this.updateIndexes(0);
15832 * Function to override to reformat the data that is sent to
15833 * the template for each node.
15834 * DEPRICATED - use the preparedata event handler.
15835 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15836 * a JSON object for an UpdateManager bound view).
15838 prepareData : function(data, index, record)
15840 this.fireEvent("preparedata", this, data, index, record);
15844 onUpdate : function(ds, record){
15845 // Roo.log('on update');
15846 this.clearSelections();
15847 var index = this.store.indexOf(record);
15848 var n = this.nodes[index];
15849 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15850 n.parentNode.removeChild(n);
15851 this.updateIndexes(index, index);
15857 onAdd : function(ds, records, index)
15859 //Roo.log(['on Add', ds, records, index] );
15860 this.clearSelections();
15861 if(this.nodes.length == 0){
15865 var n = this.nodes[index];
15866 for(var i = 0, len = records.length; i < len; i++){
15867 var d = this.prepareData(records[i].data, i, records[i]);
15869 this.tpl.insertBefore(n, d);
15872 this.tpl.append(this.el, d);
15875 this.updateIndexes(index);
15878 onRemove : function(ds, record, index){
15879 // Roo.log('onRemove');
15880 this.clearSelections();
15881 var el = this.dataName ?
15882 this.el.child('.roo-tpl-' + this.dataName) :
15885 el.dom.removeChild(this.nodes[index]);
15886 this.updateIndexes(index);
15890 * Refresh an individual node.
15891 * @param {Number} index
15893 refreshNode : function(index){
15894 this.onUpdate(this.store, this.store.getAt(index));
15897 updateIndexes : function(startIndex, endIndex){
15898 var ns = this.nodes;
15899 startIndex = startIndex || 0;
15900 endIndex = endIndex || ns.length - 1;
15901 for(var i = startIndex; i <= endIndex; i++){
15902 ns[i].nodeIndex = i;
15907 * Changes the data store this view uses and refresh the view.
15908 * @param {Store} store
15910 setStore : function(store, initial){
15911 if(!initial && this.store){
15912 this.store.un("datachanged", this.refresh);
15913 this.store.un("add", this.onAdd);
15914 this.store.un("remove", this.onRemove);
15915 this.store.un("update", this.onUpdate);
15916 this.store.un("clear", this.refresh);
15917 this.store.un("beforeload", this.onBeforeLoad);
15918 this.store.un("load", this.onLoad);
15919 this.store.un("loadexception", this.onLoad);
15923 store.on("datachanged", this.refresh, this);
15924 store.on("add", this.onAdd, this);
15925 store.on("remove", this.onRemove, this);
15926 store.on("update", this.onUpdate, this);
15927 store.on("clear", this.refresh, this);
15928 store.on("beforeload", this.onBeforeLoad, this);
15929 store.on("load", this.onLoad, this);
15930 store.on("loadexception", this.onLoad, this);
15938 * onbeforeLoad - masks the loading area.
15941 onBeforeLoad : function(store,opts)
15943 //Roo.log('onBeforeLoad');
15945 this.el.update("");
15947 this.el.mask(this.mask ? this.mask : "Loading" );
15949 onLoad : function ()
15956 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15957 * @param {HTMLElement} node
15958 * @return {HTMLElement} The template node
15960 findItemFromChild : function(node){
15961 var el = this.dataName ?
15962 this.el.child('.roo-tpl-' + this.dataName,true) :
15965 if(!node || node.parentNode == el){
15968 var p = node.parentNode;
15969 while(p && p != el){
15970 if(p.parentNode == el){
15979 onClick : function(e){
15980 var item = this.findItemFromChild(e.getTarget());
15982 var index = this.indexOf(item);
15983 if(this.onItemClick(item, index, e) !== false){
15984 this.fireEvent("click", this, index, item, e);
15987 this.clearSelections();
15992 onContextMenu : function(e){
15993 var item = this.findItemFromChild(e.getTarget());
15995 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16000 onDblClick : function(e){
16001 var item = this.findItemFromChild(e.getTarget());
16003 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16007 onItemClick : function(item, index, e)
16009 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16012 if (this.toggleSelect) {
16013 var m = this.isSelected(item) ? 'unselect' : 'select';
16016 _t[m](item, true, false);
16019 if(this.multiSelect || this.singleSelect){
16020 if(this.multiSelect && e.shiftKey && this.lastSelection){
16021 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16023 this.select(item, this.multiSelect && e.ctrlKey);
16024 this.lastSelection = item;
16027 if(!this.tickable){
16028 e.preventDefault();
16036 * Get the number of selected nodes.
16039 getSelectionCount : function(){
16040 return this.selections.length;
16044 * Get the currently selected nodes.
16045 * @return {Array} An array of HTMLElements
16047 getSelectedNodes : function(){
16048 return this.selections;
16052 * Get the indexes of the selected nodes.
16055 getSelectedIndexes : function(){
16056 var indexes = [], s = this.selections;
16057 for(var i = 0, len = s.length; i < len; i++){
16058 indexes.push(s[i].nodeIndex);
16064 * Clear all selections
16065 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16067 clearSelections : function(suppressEvent){
16068 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16069 this.cmp.elements = this.selections;
16070 this.cmp.removeClass(this.selectedClass);
16071 this.selections = [];
16072 if(!suppressEvent){
16073 this.fireEvent("selectionchange", this, this.selections);
16079 * Returns true if the passed node is selected
16080 * @param {HTMLElement/Number} node The node or node index
16081 * @return {Boolean}
16083 isSelected : function(node){
16084 var s = this.selections;
16088 node = this.getNode(node);
16089 return s.indexOf(node) !== -1;
16094 * @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
16095 * @param {Boolean} keepExisting (optional) true to keep existing selections
16096 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16098 select : function(nodeInfo, keepExisting, suppressEvent){
16099 if(nodeInfo instanceof Array){
16101 this.clearSelections(true);
16103 for(var i = 0, len = nodeInfo.length; i < len; i++){
16104 this.select(nodeInfo[i], true, true);
16108 var node = this.getNode(nodeInfo);
16109 if(!node || this.isSelected(node)){
16110 return; // already selected.
16113 this.clearSelections(true);
16116 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16117 Roo.fly(node).addClass(this.selectedClass);
16118 this.selections.push(node);
16119 if(!suppressEvent){
16120 this.fireEvent("selectionchange", this, this.selections);
16128 * @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
16129 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16130 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16132 unselect : function(nodeInfo, keepExisting, suppressEvent)
16134 if(nodeInfo instanceof Array){
16135 Roo.each(this.selections, function(s) {
16136 this.unselect(s, nodeInfo);
16140 var node = this.getNode(nodeInfo);
16141 if(!node || !this.isSelected(node)){
16142 //Roo.log("not selected");
16143 return; // not selected.
16147 Roo.each(this.selections, function(s) {
16149 Roo.fly(node).removeClass(this.selectedClass);
16156 this.selections= ns;
16157 this.fireEvent("selectionchange", this, this.selections);
16161 * Gets a template node.
16162 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16163 * @return {HTMLElement} The node or null if it wasn't found
16165 getNode : function(nodeInfo){
16166 if(typeof nodeInfo == "string"){
16167 return document.getElementById(nodeInfo);
16168 }else if(typeof nodeInfo == "number"){
16169 return this.nodes[nodeInfo];
16175 * Gets a range template nodes.
16176 * @param {Number} startIndex
16177 * @param {Number} endIndex
16178 * @return {Array} An array of nodes
16180 getNodes : function(start, end){
16181 var ns = this.nodes;
16182 start = start || 0;
16183 end = typeof end == "undefined" ? ns.length - 1 : end;
16186 for(var i = start; i <= end; i++){
16190 for(var i = start; i >= end; i--){
16198 * Finds the index of the passed node
16199 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16200 * @return {Number} The index of the node or -1
16202 indexOf : function(node){
16203 node = this.getNode(node);
16204 if(typeof node.nodeIndex == "number"){
16205 return node.nodeIndex;
16207 var ns = this.nodes;
16208 for(var i = 0, len = ns.length; i < len; i++){
16219 * based on jquery fullcalendar
16223 Roo.bootstrap = Roo.bootstrap || {};
16225 * @class Roo.bootstrap.Calendar
16226 * @extends Roo.bootstrap.Component
16227 * Bootstrap Calendar class
16228 * @cfg {Boolean} loadMask (true|false) default false
16229 * @cfg {Object} header generate the user specific header of the calendar, default false
16232 * Create a new Container
16233 * @param {Object} config The config object
16238 Roo.bootstrap.Calendar = function(config){
16239 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16243 * Fires when a date is selected
16244 * @param {DatePicker} this
16245 * @param {Date} date The selected date
16249 * @event monthchange
16250 * Fires when the displayed month changes
16251 * @param {DatePicker} this
16252 * @param {Date} date The selected month
16254 'monthchange': true,
16256 * @event evententer
16257 * Fires when mouse over an event
16258 * @param {Calendar} this
16259 * @param {event} Event
16261 'evententer': true,
16263 * @event eventleave
16264 * Fires when the mouse leaves an
16265 * @param {Calendar} this
16268 'eventleave': true,
16270 * @event eventclick
16271 * Fires when the mouse click an
16272 * @param {Calendar} this
16281 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16284 * @cfg {Number} startDay
16285 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16293 getAutoCreate : function(){
16296 var fc_button = function(name, corner, style, content ) {
16297 return Roo.apply({},{
16299 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16301 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16304 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16315 style : 'width:100%',
16322 cls : 'fc-header-left',
16324 fc_button('prev', 'left', 'arrow', '‹' ),
16325 fc_button('next', 'right', 'arrow', '›' ),
16326 { tag: 'span', cls: 'fc-header-space' },
16327 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16335 cls : 'fc-header-center',
16339 cls: 'fc-header-title',
16342 html : 'month / year'
16350 cls : 'fc-header-right',
16352 /* fc_button('month', 'left', '', 'month' ),
16353 fc_button('week', '', '', 'week' ),
16354 fc_button('day', 'right', '', 'day' )
16366 header = this.header;
16369 var cal_heads = function() {
16371 // fixme - handle this.
16373 for (var i =0; i < Date.dayNames.length; i++) {
16374 var d = Date.dayNames[i];
16377 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16378 html : d.substring(0,3)
16382 ret[0].cls += ' fc-first';
16383 ret[6].cls += ' fc-last';
16386 var cal_cell = function(n) {
16389 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16394 cls: 'fc-day-number',
16398 cls: 'fc-day-content',
16402 style: 'position: relative;' // height: 17px;
16414 var cal_rows = function() {
16417 for (var r = 0; r < 6; r++) {
16424 for (var i =0; i < Date.dayNames.length; i++) {
16425 var d = Date.dayNames[i];
16426 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16429 row.cn[0].cls+=' fc-first';
16430 row.cn[0].cn[0].style = 'min-height:90px';
16431 row.cn[6].cls+=' fc-last';
16435 ret[0].cls += ' fc-first';
16436 ret[4].cls += ' fc-prev-last';
16437 ret[5].cls += ' fc-last';
16444 cls: 'fc-border-separate',
16445 style : 'width:100%',
16453 cls : 'fc-first fc-last',
16471 cls : 'fc-content',
16472 style : "position: relative;",
16475 cls : 'fc-view fc-view-month fc-grid',
16476 style : 'position: relative',
16477 unselectable : 'on',
16480 cls : 'fc-event-container',
16481 style : 'position:absolute;z-index:8;top:0;left:0;'
16499 initEvents : function()
16502 throw "can not find store for calendar";
16508 style: "text-align:center",
16512 style: "background-color:white;width:50%;margin:250 auto",
16516 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16527 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16529 var size = this.el.select('.fc-content', true).first().getSize();
16530 this.maskEl.setSize(size.width, size.height);
16531 this.maskEl.enableDisplayMode("block");
16532 if(!this.loadMask){
16533 this.maskEl.hide();
16536 this.store = Roo.factory(this.store, Roo.data);
16537 this.store.on('load', this.onLoad, this);
16538 this.store.on('beforeload', this.onBeforeLoad, this);
16542 this.cells = this.el.select('.fc-day',true);
16543 //Roo.log(this.cells);
16544 this.textNodes = this.el.query('.fc-day-number');
16545 this.cells.addClassOnOver('fc-state-hover');
16547 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16548 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16549 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16550 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16552 this.on('monthchange', this.onMonthChange, this);
16554 this.update(new Date().clearTime());
16557 resize : function() {
16558 var sz = this.el.getSize();
16560 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16561 this.el.select('.fc-day-content div',true).setHeight(34);
16566 showPrevMonth : function(e){
16567 this.update(this.activeDate.add("mo", -1));
16569 showToday : function(e){
16570 this.update(new Date().clearTime());
16573 showNextMonth : function(e){
16574 this.update(this.activeDate.add("mo", 1));
16578 showPrevYear : function(){
16579 this.update(this.activeDate.add("y", -1));
16583 showNextYear : function(){
16584 this.update(this.activeDate.add("y", 1));
16589 update : function(date)
16591 var vd = this.activeDate;
16592 this.activeDate = date;
16593 // if(vd && this.el){
16594 // var t = date.getTime();
16595 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16596 // Roo.log('using add remove');
16598 // this.fireEvent('monthchange', this, date);
16600 // this.cells.removeClass("fc-state-highlight");
16601 // this.cells.each(function(c){
16602 // if(c.dateValue == t){
16603 // c.addClass("fc-state-highlight");
16604 // setTimeout(function(){
16605 // try{c.dom.firstChild.focus();}catch(e){}
16615 var days = date.getDaysInMonth();
16617 var firstOfMonth = date.getFirstDateOfMonth();
16618 var startingPos = firstOfMonth.getDay()-this.startDay;
16620 if(startingPos < this.startDay){
16624 var pm = date.add(Date.MONTH, -1);
16625 var prevStart = pm.getDaysInMonth()-startingPos;
16627 this.cells = this.el.select('.fc-day',true);
16628 this.textNodes = this.el.query('.fc-day-number');
16629 this.cells.addClassOnOver('fc-state-hover');
16631 var cells = this.cells.elements;
16632 var textEls = this.textNodes;
16634 Roo.each(cells, function(cell){
16635 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16638 days += startingPos;
16640 // convert everything to numbers so it's fast
16641 var day = 86400000;
16642 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16645 //Roo.log(prevStart);
16647 var today = new Date().clearTime().getTime();
16648 var sel = date.clearTime().getTime();
16649 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16650 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16651 var ddMatch = this.disabledDatesRE;
16652 var ddText = this.disabledDatesText;
16653 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16654 var ddaysText = this.disabledDaysText;
16655 var format = this.format;
16657 var setCellClass = function(cal, cell){
16661 //Roo.log('set Cell Class');
16663 var t = d.getTime();
16667 cell.dateValue = t;
16669 cell.className += " fc-today";
16670 cell.className += " fc-state-highlight";
16671 cell.title = cal.todayText;
16674 // disable highlight in other month..
16675 //cell.className += " fc-state-highlight";
16680 cell.className = " fc-state-disabled";
16681 cell.title = cal.minText;
16685 cell.className = " fc-state-disabled";
16686 cell.title = cal.maxText;
16690 if(ddays.indexOf(d.getDay()) != -1){
16691 cell.title = ddaysText;
16692 cell.className = " fc-state-disabled";
16695 if(ddMatch && format){
16696 var fvalue = d.dateFormat(format);
16697 if(ddMatch.test(fvalue)){
16698 cell.title = ddText.replace("%0", fvalue);
16699 cell.className = " fc-state-disabled";
16703 if (!cell.initialClassName) {
16704 cell.initialClassName = cell.dom.className;
16707 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16712 for(; i < startingPos; i++) {
16713 textEls[i].innerHTML = (++prevStart);
16714 d.setDate(d.getDate()+1);
16716 cells[i].className = "fc-past fc-other-month";
16717 setCellClass(this, cells[i]);
16722 for(; i < days; i++){
16723 intDay = i - startingPos + 1;
16724 textEls[i].innerHTML = (intDay);
16725 d.setDate(d.getDate()+1);
16727 cells[i].className = ''; // "x-date-active";
16728 setCellClass(this, cells[i]);
16732 for(; i < 42; i++) {
16733 textEls[i].innerHTML = (++extraDays);
16734 d.setDate(d.getDate()+1);
16736 cells[i].className = "fc-future fc-other-month";
16737 setCellClass(this, cells[i]);
16740 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16742 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16744 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16745 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16747 if(totalRows != 6){
16748 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16749 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16752 this.fireEvent('monthchange', this, date);
16756 if(!this.internalRender){
16757 var main = this.el.dom.firstChild;
16758 var w = main.offsetWidth;
16759 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16760 Roo.fly(main).setWidth(w);
16761 this.internalRender = true;
16762 // opera does not respect the auto grow header center column
16763 // then, after it gets a width opera refuses to recalculate
16764 // without a second pass
16765 if(Roo.isOpera && !this.secondPass){
16766 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16767 this.secondPass = true;
16768 this.update.defer(10, this, [date]);
16775 findCell : function(dt) {
16776 dt = dt.clearTime().getTime();
16778 this.cells.each(function(c){
16779 //Roo.log("check " +c.dateValue + '?=' + dt);
16780 if(c.dateValue == dt){
16790 findCells : function(ev) {
16791 var s = ev.start.clone().clearTime().getTime();
16793 var e= ev.end.clone().clearTime().getTime();
16796 this.cells.each(function(c){
16797 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16799 if(c.dateValue > e){
16802 if(c.dateValue < s){
16811 // findBestRow: function(cells)
16815 // for (var i =0 ; i < cells.length;i++) {
16816 // ret = Math.max(cells[i].rows || 0,ret);
16823 addItem : function(ev)
16825 // look for vertical location slot in
16826 var cells = this.findCells(ev);
16828 // ev.row = this.findBestRow(cells);
16830 // work out the location.
16834 for(var i =0; i < cells.length; i++) {
16836 cells[i].row = cells[0].row;
16839 cells[i].row = cells[i].row + 1;
16849 if (crow.start.getY() == cells[i].getY()) {
16851 crow.end = cells[i];
16868 cells[0].events.push(ev);
16870 this.calevents.push(ev);
16873 clearEvents: function() {
16875 if(!this.calevents){
16879 Roo.each(this.cells.elements, function(c){
16885 Roo.each(this.calevents, function(e) {
16886 Roo.each(e.els, function(el) {
16887 el.un('mouseenter' ,this.onEventEnter, this);
16888 el.un('mouseleave' ,this.onEventLeave, this);
16893 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16899 renderEvents: function()
16903 this.cells.each(function(c) {
16912 if(c.row != c.events.length){
16913 r = 4 - (4 - (c.row - c.events.length));
16916 c.events = ev.slice(0, r);
16917 c.more = ev.slice(r);
16919 if(c.more.length && c.more.length == 1){
16920 c.events.push(c.more.pop());
16923 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16927 this.cells.each(function(c) {
16929 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16932 for (var e = 0; e < c.events.length; e++){
16933 var ev = c.events[e];
16934 var rows = ev.rows;
16936 for(var i = 0; i < rows.length; i++) {
16938 // how many rows should it span..
16941 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16942 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16944 unselectable : "on",
16947 cls: 'fc-event-inner',
16951 // cls: 'fc-event-time',
16952 // html : cells.length > 1 ? '' : ev.time
16956 cls: 'fc-event-title',
16957 html : String.format('{0}', ev.title)
16964 cls: 'ui-resizable-handle ui-resizable-e',
16965 html : '  '
16972 cfg.cls += ' fc-event-start';
16974 if ((i+1) == rows.length) {
16975 cfg.cls += ' fc-event-end';
16978 var ctr = _this.el.select('.fc-event-container',true).first();
16979 var cg = ctr.createChild(cfg);
16981 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16982 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16984 var r = (c.more.length) ? 1 : 0;
16985 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16986 cg.setWidth(ebox.right - sbox.x -2);
16988 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16989 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16990 cg.on('click', _this.onEventClick, _this, ev);
17001 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17002 style : 'position: absolute',
17003 unselectable : "on",
17006 cls: 'fc-event-inner',
17010 cls: 'fc-event-title',
17018 cls: 'ui-resizable-handle ui-resizable-e',
17019 html : '  '
17025 var ctr = _this.el.select('.fc-event-container',true).first();
17026 var cg = ctr.createChild(cfg);
17028 var sbox = c.select('.fc-day-content',true).first().getBox();
17029 var ebox = c.select('.fc-day-content',true).first().getBox();
17031 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17032 cg.setWidth(ebox.right - sbox.x -2);
17034 cg.on('click', _this.onMoreEventClick, _this, c.more);
17044 onEventEnter: function (e, el,event,d) {
17045 this.fireEvent('evententer', this, el, event);
17048 onEventLeave: function (e, el,event,d) {
17049 this.fireEvent('eventleave', this, el, event);
17052 onEventClick: function (e, el,event,d) {
17053 this.fireEvent('eventclick', this, el, event);
17056 onMonthChange: function () {
17060 onMoreEventClick: function(e, el, more)
17064 this.calpopover.placement = 'right';
17065 this.calpopover.setTitle('More');
17067 this.calpopover.setContent('');
17069 var ctr = this.calpopover.el.select('.popover-content', true).first();
17071 Roo.each(more, function(m){
17073 cls : 'fc-event-hori fc-event-draggable',
17076 var cg = ctr.createChild(cfg);
17078 cg.on('click', _this.onEventClick, _this, m);
17081 this.calpopover.show(el);
17086 onLoad: function ()
17088 this.calevents = [];
17091 if(this.store.getCount() > 0){
17092 this.store.data.each(function(d){
17095 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17096 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17097 time : d.data.start_time,
17098 title : d.data.title,
17099 description : d.data.description,
17100 venue : d.data.venue
17105 this.renderEvents();
17107 if(this.calevents.length && this.loadMask){
17108 this.maskEl.hide();
17112 onBeforeLoad: function()
17114 this.clearEvents();
17116 this.maskEl.show();
17130 * @class Roo.bootstrap.Popover
17131 * @extends Roo.bootstrap.Component
17132 * Bootstrap Popover class
17133 * @cfg {String} html contents of the popover (or false to use children..)
17134 * @cfg {String} title of popover (or false to hide)
17135 * @cfg {String} placement how it is placed
17136 * @cfg {String} trigger click || hover (or false to trigger manually)
17137 * @cfg {String} over what (parent or false to trigger manually.)
17138 * @cfg {Number} delay - delay before showing
17141 * Create a new Popover
17142 * @param {Object} config The config object
17145 Roo.bootstrap.Popover = function(config){
17146 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17152 * After the popover show
17154 * @param {Roo.bootstrap.Popover} this
17159 * After the popover hide
17161 * @param {Roo.bootstrap.Popover} this
17167 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17169 title: 'Fill in a title',
17172 placement : 'right',
17173 trigger : 'hover', // hover
17179 can_build_overlaid : false,
17181 getChildContainer : function()
17183 return this.el.select('.popover-content',true).first();
17186 getAutoCreate : function(){
17189 cls : 'popover roo-dynamic',
17190 style: 'display:block',
17196 cls : 'popover-inner',
17200 cls: 'popover-title',
17204 cls : 'popover-content',
17215 setTitle: function(str)
17218 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17220 setContent: function(str)
17223 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17225 // as it get's added to the bottom of the page.
17226 onRender : function(ct, position)
17228 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17230 var cfg = Roo.apply({}, this.getAutoCreate());
17234 cfg.cls += ' ' + this.cls;
17237 cfg.style = this.style;
17239 //Roo.log("adding to ");
17240 this.el = Roo.get(document.body).createChild(cfg, position);
17241 // Roo.log(this.el);
17246 initEvents : function()
17248 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17249 this.el.enableDisplayMode('block');
17251 if (this.over === false) {
17254 if (this.triggers === false) {
17257 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17258 var triggers = this.trigger ? this.trigger.split(' ') : [];
17259 Roo.each(triggers, function(trigger) {
17261 if (trigger == 'click') {
17262 on_el.on('click', this.toggle, this);
17263 } else if (trigger != 'manual') {
17264 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17265 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17267 on_el.on(eventIn ,this.enter, this);
17268 on_el.on(eventOut, this.leave, this);
17279 toggle : function () {
17280 this.hoverState == 'in' ? this.leave() : this.enter();
17283 enter : function () {
17285 clearTimeout(this.timeout);
17287 this.hoverState = 'in';
17289 if (!this.delay || !this.delay.show) {
17294 this.timeout = setTimeout(function () {
17295 if (_t.hoverState == 'in') {
17298 }, this.delay.show)
17301 leave : function() {
17302 clearTimeout(this.timeout);
17304 this.hoverState = 'out';
17306 if (!this.delay || !this.delay.hide) {
17311 this.timeout = setTimeout(function () {
17312 if (_t.hoverState == 'out') {
17315 }, this.delay.hide)
17318 show : function (on_el)
17321 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17325 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17326 if (this.html !== false) {
17327 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17329 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17330 if (!this.title.length) {
17331 this.el.select('.popover-title',true).hide();
17334 var placement = typeof this.placement == 'function' ?
17335 this.placement.call(this, this.el, on_el) :
17338 var autoToken = /\s?auto?\s?/i;
17339 var autoPlace = autoToken.test(placement);
17341 placement = placement.replace(autoToken, '') || 'top';
17345 //this.el.setXY([0,0]);
17347 this.el.dom.style.display='block';
17348 this.el.addClass(placement);
17350 //this.el.appendTo(on_el);
17352 var p = this.getPosition();
17353 var box = this.el.getBox();
17358 var align = Roo.bootstrap.Popover.alignment[placement];
17361 this.el.alignTo(on_el, align[0],align[1]);
17362 //var arrow = this.el.select('.arrow',true).first();
17363 //arrow.set(align[2],
17365 this.el.addClass('in');
17368 if (this.el.hasClass('fade')) {
17372 this.hoverState = 'in';
17374 this.fireEvent('show', this);
17379 this.el.setXY([0,0]);
17380 this.el.removeClass('in');
17382 this.hoverState = null;
17384 this.fireEvent('hide', this);
17389 Roo.bootstrap.Popover.alignment = {
17390 'left' : ['r-l', [-10,0], 'right'],
17391 'right' : ['l-r', [10,0], 'left'],
17392 'bottom' : ['t-b', [0,10], 'top'],
17393 'top' : [ 'b-t', [0,-10], 'bottom']
17404 * @class Roo.bootstrap.Progress
17405 * @extends Roo.bootstrap.Component
17406 * Bootstrap Progress class
17407 * @cfg {Boolean} striped striped of the progress bar
17408 * @cfg {Boolean} active animated of the progress bar
17412 * Create a new Progress
17413 * @param {Object} config The config object
17416 Roo.bootstrap.Progress = function(config){
17417 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17420 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17425 getAutoCreate : function(){
17433 cfg.cls += ' progress-striped';
17437 cfg.cls += ' active';
17456 * @class Roo.bootstrap.ProgressBar
17457 * @extends Roo.bootstrap.Component
17458 * Bootstrap ProgressBar class
17459 * @cfg {Number} aria_valuenow aria-value now
17460 * @cfg {Number} aria_valuemin aria-value min
17461 * @cfg {Number} aria_valuemax aria-value max
17462 * @cfg {String} label label for the progress bar
17463 * @cfg {String} panel (success | info | warning | danger )
17464 * @cfg {String} role role of the progress bar
17465 * @cfg {String} sr_only text
17469 * Create a new ProgressBar
17470 * @param {Object} config The config object
17473 Roo.bootstrap.ProgressBar = function(config){
17474 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17477 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17481 aria_valuemax : 100,
17487 getAutoCreate : function()
17492 cls: 'progress-bar',
17493 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17505 cfg.role = this.role;
17508 if(this.aria_valuenow){
17509 cfg['aria-valuenow'] = this.aria_valuenow;
17512 if(this.aria_valuemin){
17513 cfg['aria-valuemin'] = this.aria_valuemin;
17516 if(this.aria_valuemax){
17517 cfg['aria-valuemax'] = this.aria_valuemax;
17520 if(this.label && !this.sr_only){
17521 cfg.html = this.label;
17525 cfg.cls += ' progress-bar-' + this.panel;
17531 update : function(aria_valuenow)
17533 this.aria_valuenow = aria_valuenow;
17535 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17550 * @class Roo.bootstrap.TabGroup
17551 * @extends Roo.bootstrap.Column
17552 * Bootstrap Column class
17553 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17554 * @cfg {Boolean} carousel true to make the group behave like a carousel
17555 * @cfg {Boolean} bullets show bullets for the panels
17556 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17557 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17558 * @cfg {Boolean} showarrow (true|false) show arrow default true
17561 * Create a new TabGroup
17562 * @param {Object} config The config object
17565 Roo.bootstrap.TabGroup = function(config){
17566 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17568 this.navId = Roo.id();
17571 Roo.bootstrap.TabGroup.register(this);
17575 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17578 transition : false,
17583 slideOnTouch : false,
17586 getAutoCreate : function()
17588 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17590 cfg.cls += ' tab-content';
17592 if (this.carousel) {
17593 cfg.cls += ' carousel slide';
17596 cls : 'carousel-inner',
17600 if(this.bullets && !Roo.isTouch){
17603 cls : 'carousel-bullets',
17607 if(this.bullets_cls){
17608 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17615 cfg.cn[0].cn.push(bullets);
17618 if(this.showarrow){
17619 cfg.cn[0].cn.push({
17621 class : 'carousel-arrow',
17625 class : 'carousel-prev',
17629 class : 'fa fa-chevron-left'
17635 class : 'carousel-next',
17639 class : 'fa fa-chevron-right'
17652 initEvents: function()
17654 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17655 // this.el.on("touchstart", this.onTouchStart, this);
17658 if(this.autoslide){
17661 this.slideFn = window.setInterval(function() {
17662 _this.showPanelNext();
17666 if(this.showarrow){
17667 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17668 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17674 // onTouchStart : function(e, el, o)
17676 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17680 // this.showPanelNext();
17684 getChildContainer : function()
17686 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17690 * register a Navigation item
17691 * @param {Roo.bootstrap.NavItem} the navitem to add
17693 register : function(item)
17695 this.tabs.push( item);
17696 item.navId = this.navId; // not really needed..
17701 getActivePanel : function()
17704 Roo.each(this.tabs, function(t) {
17714 getPanelByName : function(n)
17717 Roo.each(this.tabs, function(t) {
17718 if (t.tabId == n) {
17726 indexOfPanel : function(p)
17729 Roo.each(this.tabs, function(t,i) {
17730 if (t.tabId == p.tabId) {
17739 * show a specific panel
17740 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17741 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17743 showPanel : function (pan)
17745 if(this.transition || typeof(pan) == 'undefined'){
17746 Roo.log("waiting for the transitionend");
17750 if (typeof(pan) == 'number') {
17751 pan = this.tabs[pan];
17754 if (typeof(pan) == 'string') {
17755 pan = this.getPanelByName(pan);
17758 var cur = this.getActivePanel();
17761 Roo.log('pan or acitve pan is undefined');
17765 if (pan.tabId == this.getActivePanel().tabId) {
17769 if (false === cur.fireEvent('beforedeactivate')) {
17773 if(this.bullets > 0 && !Roo.isTouch){
17774 this.setActiveBullet(this.indexOfPanel(pan));
17777 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17779 this.transition = true;
17780 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17781 var lr = dir == 'next' ? 'left' : 'right';
17782 pan.el.addClass(dir); // or prev
17783 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17784 cur.el.addClass(lr); // or right
17785 pan.el.addClass(lr);
17788 cur.el.on('transitionend', function() {
17789 Roo.log("trans end?");
17791 pan.el.removeClass([lr,dir]);
17792 pan.setActive(true);
17794 cur.el.removeClass([lr]);
17795 cur.setActive(false);
17797 _this.transition = false;
17799 }, this, { single: true } );
17804 cur.setActive(false);
17805 pan.setActive(true);
17810 showPanelNext : function()
17812 var i = this.indexOfPanel(this.getActivePanel());
17814 if (i >= this.tabs.length - 1 && !this.autoslide) {
17818 if (i >= this.tabs.length - 1 && this.autoslide) {
17822 this.showPanel(this.tabs[i+1]);
17825 showPanelPrev : function()
17827 var i = this.indexOfPanel(this.getActivePanel());
17829 if (i < 1 && !this.autoslide) {
17833 if (i < 1 && this.autoslide) {
17834 i = this.tabs.length;
17837 this.showPanel(this.tabs[i-1]);
17841 addBullet: function()
17843 if(!this.bullets || Roo.isTouch){
17846 var ctr = this.el.select('.carousel-bullets',true).first();
17847 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17848 var bullet = ctr.createChild({
17849 cls : 'bullet bullet-' + i
17850 },ctr.dom.lastChild);
17855 bullet.on('click', (function(e, el, o, ii, t){
17857 e.preventDefault();
17859 this.showPanel(ii);
17861 if(this.autoslide && this.slideFn){
17862 clearInterval(this.slideFn);
17863 this.slideFn = window.setInterval(function() {
17864 _this.showPanelNext();
17868 }).createDelegate(this, [i, bullet], true));
17873 setActiveBullet : function(i)
17879 Roo.each(this.el.select('.bullet', true).elements, function(el){
17880 el.removeClass('selected');
17883 var bullet = this.el.select('.bullet-' + i, true).first();
17889 bullet.addClass('selected');
17900 Roo.apply(Roo.bootstrap.TabGroup, {
17904 * register a Navigation Group
17905 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17907 register : function(navgrp)
17909 this.groups[navgrp.navId] = navgrp;
17913 * fetch a Navigation Group based on the navigation ID
17914 * if one does not exist , it will get created.
17915 * @param {string} the navgroup to add
17916 * @returns {Roo.bootstrap.NavGroup} the navgroup
17918 get: function(navId) {
17919 if (typeof(this.groups[navId]) == 'undefined') {
17920 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17922 return this.groups[navId] ;
17937 * @class Roo.bootstrap.TabPanel
17938 * @extends Roo.bootstrap.Component
17939 * Bootstrap TabPanel class
17940 * @cfg {Boolean} active panel active
17941 * @cfg {String} html panel content
17942 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17943 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17944 * @cfg {String} href click to link..
17948 * Create a new TabPanel
17949 * @param {Object} config The config object
17952 Roo.bootstrap.TabPanel = function(config){
17953 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17957 * Fires when the active status changes
17958 * @param {Roo.bootstrap.TabPanel} this
17959 * @param {Boolean} state the new state
17964 * @event beforedeactivate
17965 * Fires before a tab is de-activated - can be used to do validation on a form.
17966 * @param {Roo.bootstrap.TabPanel} this
17967 * @return {Boolean} false if there is an error
17970 'beforedeactivate': true
17973 this.tabId = this.tabId || Roo.id();
17977 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17985 getAutoCreate : function(){
17988 // item is needed for carousel - not sure if it has any effect otherwise
17989 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17990 html: this.html || ''
17994 cfg.cls += ' active';
17998 cfg.tabId = this.tabId;
18005 initEvents: function()
18007 var p = this.parent();
18009 this.navId = this.navId || p.navId;
18011 if (typeof(this.navId) != 'undefined') {
18012 // not really needed.. but just in case.. parent should be a NavGroup.
18013 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18017 var i = tg.tabs.length - 1;
18019 if(this.active && tg.bullets > 0 && i < tg.bullets){
18020 tg.setActiveBullet(i);
18024 this.el.on('click', this.onClick, this);
18027 this.el.on("touchstart", this.onTouchStart, this);
18028 this.el.on("touchmove", this.onTouchMove, this);
18029 this.el.on("touchend", this.onTouchEnd, this);
18034 onRender : function(ct, position)
18036 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18039 setActive : function(state)
18041 Roo.log("panel - set active " + this.tabId + "=" + state);
18043 this.active = state;
18045 this.el.removeClass('active');
18047 } else if (!this.el.hasClass('active')) {
18048 this.el.addClass('active');
18051 this.fireEvent('changed', this, state);
18054 onClick : function(e)
18056 e.preventDefault();
18058 if(!this.href.length){
18062 window.location.href = this.href;
18071 onTouchStart : function(e)
18073 this.swiping = false;
18075 this.startX = e.browserEvent.touches[0].clientX;
18076 this.startY = e.browserEvent.touches[0].clientY;
18079 onTouchMove : function(e)
18081 this.swiping = true;
18083 this.endX = e.browserEvent.touches[0].clientX;
18084 this.endY = e.browserEvent.touches[0].clientY;
18087 onTouchEnd : function(e)
18094 var tabGroup = this.parent();
18096 if(this.endX > this.startX){ // swiping right
18097 tabGroup.showPanelPrev();
18101 if(this.startX > this.endX){ // swiping left
18102 tabGroup.showPanelNext();
18121 * @class Roo.bootstrap.DateField
18122 * @extends Roo.bootstrap.Input
18123 * Bootstrap DateField class
18124 * @cfg {Number} weekStart default 0
18125 * @cfg {String} viewMode default empty, (months|years)
18126 * @cfg {String} minViewMode default empty, (months|years)
18127 * @cfg {Number} startDate default -Infinity
18128 * @cfg {Number} endDate default Infinity
18129 * @cfg {Boolean} todayHighlight default false
18130 * @cfg {Boolean} todayBtn default false
18131 * @cfg {Boolean} calendarWeeks default false
18132 * @cfg {Object} daysOfWeekDisabled default empty
18133 * @cfg {Boolean} singleMode default false (true | false)
18135 * @cfg {Boolean} keyboardNavigation default true
18136 * @cfg {String} language default en
18139 * Create a new DateField
18140 * @param {Object} config The config object
18143 Roo.bootstrap.DateField = function(config){
18144 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18148 * Fires when this field show.
18149 * @param {Roo.bootstrap.DateField} this
18150 * @param {Mixed} date The date value
18155 * Fires when this field hide.
18156 * @param {Roo.bootstrap.DateField} this
18157 * @param {Mixed} date The date value
18162 * Fires when select a date.
18163 * @param {Roo.bootstrap.DateField} this
18164 * @param {Mixed} date The date value
18168 * @event beforeselect
18169 * Fires when before select a date.
18170 * @param {Roo.bootstrap.DateField} this
18171 * @param {Mixed} date The date value
18173 beforeselect : true
18177 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18180 * @cfg {String} format
18181 * The default date format string which can be overriden for localization support. The format must be
18182 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18186 * @cfg {String} altFormats
18187 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18188 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18190 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18198 todayHighlight : false,
18204 keyboardNavigation: true,
18206 calendarWeeks: false,
18208 startDate: -Infinity,
18212 daysOfWeekDisabled: [],
18216 singleMode : false,
18218 UTCDate: function()
18220 return new Date(Date.UTC.apply(Date, arguments));
18223 UTCToday: function()
18225 var today = new Date();
18226 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18229 getDate: function() {
18230 var d = this.getUTCDate();
18231 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18234 getUTCDate: function() {
18238 setDate: function(d) {
18239 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18242 setUTCDate: function(d) {
18244 this.setValue(this.formatDate(this.date));
18247 onRender: function(ct, position)
18250 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18252 this.language = this.language || 'en';
18253 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18254 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18256 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18257 this.format = this.format || 'm/d/y';
18258 this.isInline = false;
18259 this.isInput = true;
18260 this.component = this.el.select('.add-on', true).first() || false;
18261 this.component = (this.component && this.component.length === 0) ? false : this.component;
18262 this.hasInput = this.component && this.inputEl().length;
18264 if (typeof(this.minViewMode === 'string')) {
18265 switch (this.minViewMode) {
18267 this.minViewMode = 1;
18270 this.minViewMode = 2;
18273 this.minViewMode = 0;
18278 if (typeof(this.viewMode === 'string')) {
18279 switch (this.viewMode) {
18292 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18294 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18296 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18298 this.picker().on('mousedown', this.onMousedown, this);
18299 this.picker().on('click', this.onClick, this);
18301 this.picker().addClass('datepicker-dropdown');
18303 this.startViewMode = this.viewMode;
18305 if(this.singleMode){
18306 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18307 v.setVisibilityMode(Roo.Element.DISPLAY);
18311 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18312 v.setStyle('width', '189px');
18316 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18317 if(!this.calendarWeeks){
18322 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18323 v.attr('colspan', function(i, val){
18324 return parseInt(val) + 1;
18329 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18331 this.setStartDate(this.startDate);
18332 this.setEndDate(this.endDate);
18334 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18341 if(this.isInline) {
18346 picker : function()
18348 return this.pickerEl;
18349 // return this.el.select('.datepicker', true).first();
18352 fillDow: function()
18354 var dowCnt = this.weekStart;
18363 if(this.calendarWeeks){
18371 while (dowCnt < this.weekStart + 7) {
18375 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18379 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18382 fillMonths: function()
18385 var months = this.picker().select('>.datepicker-months td', true).first();
18387 months.dom.innerHTML = '';
18393 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18396 months.createChild(month);
18403 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;
18405 if (this.date < this.startDate) {
18406 this.viewDate = new Date(this.startDate);
18407 } else if (this.date > this.endDate) {
18408 this.viewDate = new Date(this.endDate);
18410 this.viewDate = new Date(this.date);
18418 var d = new Date(this.viewDate),
18419 year = d.getUTCFullYear(),
18420 month = d.getUTCMonth(),
18421 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18422 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18423 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18424 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18425 currentDate = this.date && this.date.valueOf(),
18426 today = this.UTCToday();
18428 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18430 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18432 // this.picker.select('>tfoot th.today').
18433 // .text(dates[this.language].today)
18434 // .toggle(this.todayBtn !== false);
18436 this.updateNavArrows();
18439 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18441 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18443 prevMonth.setUTCDate(day);
18445 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18447 var nextMonth = new Date(prevMonth);
18449 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18451 nextMonth = nextMonth.valueOf();
18453 var fillMonths = false;
18455 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18457 while(prevMonth.valueOf() < nextMonth) {
18460 if (prevMonth.getUTCDay() === this.weekStart) {
18462 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18470 if(this.calendarWeeks){
18471 // ISO 8601: First week contains first thursday.
18472 // ISO also states week starts on Monday, but we can be more abstract here.
18474 // Start of current week: based on weekstart/current date
18475 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18476 // Thursday of this week
18477 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18478 // First Thursday of year, year from thursday
18479 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18480 // Calendar week: ms between thursdays, div ms per day, div 7 days
18481 calWeek = (th - yth) / 864e5 / 7 + 1;
18483 fillMonths.cn.push({
18491 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18493 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18496 if (this.todayHighlight &&
18497 prevMonth.getUTCFullYear() == today.getFullYear() &&
18498 prevMonth.getUTCMonth() == today.getMonth() &&
18499 prevMonth.getUTCDate() == today.getDate()) {
18500 clsName += ' today';
18503 if (currentDate && prevMonth.valueOf() === currentDate) {
18504 clsName += ' active';
18507 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18508 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18509 clsName += ' disabled';
18512 fillMonths.cn.push({
18514 cls: 'day ' + clsName,
18515 html: prevMonth.getDate()
18518 prevMonth.setDate(prevMonth.getDate()+1);
18521 var currentYear = this.date && this.date.getUTCFullYear();
18522 var currentMonth = this.date && this.date.getUTCMonth();
18524 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18526 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18527 v.removeClass('active');
18529 if(currentYear === year && k === currentMonth){
18530 v.addClass('active');
18533 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18534 v.addClass('disabled');
18540 year = parseInt(year/10, 10) * 10;
18542 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18544 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18547 for (var i = -1; i < 11; i++) {
18548 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18550 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18558 showMode: function(dir)
18561 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18564 Roo.each(this.picker().select('>div',true).elements, function(v){
18565 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18568 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18573 if(this.isInline) {
18577 this.picker().removeClass(['bottom', 'top']);
18579 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18581 * place to the top of element!
18585 this.picker().addClass('top');
18586 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18591 this.picker().addClass('bottom');
18593 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18596 parseDate : function(value)
18598 if(!value || value instanceof Date){
18601 var v = Date.parseDate(value, this.format);
18602 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18603 v = Date.parseDate(value, 'Y-m-d');
18605 if(!v && this.altFormats){
18606 if(!this.altFormatsArray){
18607 this.altFormatsArray = this.altFormats.split("|");
18609 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18610 v = Date.parseDate(value, this.altFormatsArray[i]);
18616 formatDate : function(date, fmt)
18618 return (!date || !(date instanceof Date)) ?
18619 date : date.dateFormat(fmt || this.format);
18622 onFocus : function()
18624 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18628 onBlur : function()
18630 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18632 var d = this.inputEl().getValue();
18641 this.picker().show();
18645 this.fireEvent('show', this, this.date);
18650 if(this.isInline) {
18653 this.picker().hide();
18654 this.viewMode = this.startViewMode;
18657 this.fireEvent('hide', this, this.date);
18661 onMousedown: function(e)
18663 e.stopPropagation();
18664 e.preventDefault();
18669 Roo.bootstrap.DateField.superclass.keyup.call(this);
18673 setValue: function(v)
18675 if(this.fireEvent('beforeselect', this, v) !== false){
18676 var d = new Date(this.parseDate(v) ).clearTime();
18678 if(isNaN(d.getTime())){
18679 this.date = this.viewDate = '';
18680 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18684 v = this.formatDate(d);
18686 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18688 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18692 this.fireEvent('select', this, this.date);
18696 getValue: function()
18698 return this.formatDate(this.date);
18701 fireKey: function(e)
18703 if (!this.picker().isVisible()){
18704 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18710 var dateChanged = false,
18712 newDate, newViewDate;
18717 e.preventDefault();
18721 if (!this.keyboardNavigation) {
18724 dir = e.keyCode == 37 ? -1 : 1;
18727 newDate = this.moveYear(this.date, dir);
18728 newViewDate = this.moveYear(this.viewDate, dir);
18729 } else if (e.shiftKey){
18730 newDate = this.moveMonth(this.date, dir);
18731 newViewDate = this.moveMonth(this.viewDate, dir);
18733 newDate = new Date(this.date);
18734 newDate.setUTCDate(this.date.getUTCDate() + dir);
18735 newViewDate = new Date(this.viewDate);
18736 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18738 if (this.dateWithinRange(newDate)){
18739 this.date = newDate;
18740 this.viewDate = newViewDate;
18741 this.setValue(this.formatDate(this.date));
18743 e.preventDefault();
18744 dateChanged = true;
18749 if (!this.keyboardNavigation) {
18752 dir = e.keyCode == 38 ? -1 : 1;
18754 newDate = this.moveYear(this.date, dir);
18755 newViewDate = this.moveYear(this.viewDate, dir);
18756 } else if (e.shiftKey){
18757 newDate = this.moveMonth(this.date, dir);
18758 newViewDate = this.moveMonth(this.viewDate, dir);
18760 newDate = new Date(this.date);
18761 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18762 newViewDate = new Date(this.viewDate);
18763 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18765 if (this.dateWithinRange(newDate)){
18766 this.date = newDate;
18767 this.viewDate = newViewDate;
18768 this.setValue(this.formatDate(this.date));
18770 e.preventDefault();
18771 dateChanged = true;
18775 this.setValue(this.formatDate(this.date));
18777 e.preventDefault();
18780 this.setValue(this.formatDate(this.date));
18794 onClick: function(e)
18796 e.stopPropagation();
18797 e.preventDefault();
18799 var target = e.getTarget();
18801 if(target.nodeName.toLowerCase() === 'i'){
18802 target = Roo.get(target).dom.parentNode;
18805 var nodeName = target.nodeName;
18806 var className = target.className;
18807 var html = target.innerHTML;
18808 //Roo.log(nodeName);
18810 switch(nodeName.toLowerCase()) {
18812 switch(className) {
18818 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18819 switch(this.viewMode){
18821 this.viewDate = this.moveMonth(this.viewDate, dir);
18825 this.viewDate = this.moveYear(this.viewDate, dir);
18831 var date = new Date();
18832 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18834 this.setValue(this.formatDate(this.date));
18841 if (className.indexOf('disabled') < 0) {
18842 this.viewDate.setUTCDate(1);
18843 if (className.indexOf('month') > -1) {
18844 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18846 var year = parseInt(html, 10) || 0;
18847 this.viewDate.setUTCFullYear(year);
18851 if(this.singleMode){
18852 this.setValue(this.formatDate(this.viewDate));
18863 //Roo.log(className);
18864 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18865 var day = parseInt(html, 10) || 1;
18866 var year = this.viewDate.getUTCFullYear(),
18867 month = this.viewDate.getUTCMonth();
18869 if (className.indexOf('old') > -1) {
18876 } else if (className.indexOf('new') > -1) {
18884 //Roo.log([year,month,day]);
18885 this.date = this.UTCDate(year, month, day,0,0,0,0);
18886 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18888 //Roo.log(this.formatDate(this.date));
18889 this.setValue(this.formatDate(this.date));
18896 setStartDate: function(startDate)
18898 this.startDate = startDate || -Infinity;
18899 if (this.startDate !== -Infinity) {
18900 this.startDate = this.parseDate(this.startDate);
18903 this.updateNavArrows();
18906 setEndDate: function(endDate)
18908 this.endDate = endDate || Infinity;
18909 if (this.endDate !== Infinity) {
18910 this.endDate = this.parseDate(this.endDate);
18913 this.updateNavArrows();
18916 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18918 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18919 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18920 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18922 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18923 return parseInt(d, 10);
18926 this.updateNavArrows();
18929 updateNavArrows: function()
18931 if(this.singleMode){
18935 var d = new Date(this.viewDate),
18936 year = d.getUTCFullYear(),
18937 month = d.getUTCMonth();
18939 Roo.each(this.picker().select('.prev', true).elements, function(v){
18941 switch (this.viewMode) {
18944 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18950 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18957 Roo.each(this.picker().select('.next', true).elements, function(v){
18959 switch (this.viewMode) {
18962 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18968 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18976 moveMonth: function(date, dir)
18981 var new_date = new Date(date.valueOf()),
18982 day = new_date.getUTCDate(),
18983 month = new_date.getUTCMonth(),
18984 mag = Math.abs(dir),
18986 dir = dir > 0 ? 1 : -1;
18989 // If going back one month, make sure month is not current month
18990 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18992 return new_date.getUTCMonth() == month;
18994 // If going forward one month, make sure month is as expected
18995 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18997 return new_date.getUTCMonth() != new_month;
18999 new_month = month + dir;
19000 new_date.setUTCMonth(new_month);
19001 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19002 if (new_month < 0 || new_month > 11) {
19003 new_month = (new_month + 12) % 12;
19006 // For magnitudes >1, move one month at a time...
19007 for (var i=0; i<mag; i++) {
19008 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19009 new_date = this.moveMonth(new_date, dir);
19011 // ...then reset the day, keeping it in the new month
19012 new_month = new_date.getUTCMonth();
19013 new_date.setUTCDate(day);
19015 return new_month != new_date.getUTCMonth();
19018 // Common date-resetting loop -- if date is beyond end of month, make it
19021 new_date.setUTCDate(--day);
19022 new_date.setUTCMonth(new_month);
19027 moveYear: function(date, dir)
19029 return this.moveMonth(date, dir*12);
19032 dateWithinRange: function(date)
19034 return date >= this.startDate && date <= this.endDate;
19040 this.picker().remove();
19043 validateValue : function(value)
19045 if(value.length < 1) {
19046 if(this.allowBlank){
19052 if(value.length < this.minLength){
19055 if(value.length > this.maxLength){
19059 var vt = Roo.form.VTypes;
19060 if(!vt[this.vtype](value, this)){
19064 if(typeof this.validator == "function"){
19065 var msg = this.validator(value);
19071 if(this.regex && !this.regex.test(value)){
19075 if(typeof(this.parseDate(value)) == 'undefined'){
19079 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19083 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19093 Roo.apply(Roo.bootstrap.DateField, {
19104 html: '<i class="fa fa-arrow-left"/>'
19114 html: '<i class="fa fa-arrow-right"/>'
19156 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19157 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19158 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19159 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19160 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19173 navFnc: 'FullYear',
19178 navFnc: 'FullYear',
19183 Roo.apply(Roo.bootstrap.DateField, {
19187 cls: 'datepicker dropdown-menu roo-dynamic',
19191 cls: 'datepicker-days',
19195 cls: 'table-condensed',
19197 Roo.bootstrap.DateField.head,
19201 Roo.bootstrap.DateField.footer
19208 cls: 'datepicker-months',
19212 cls: 'table-condensed',
19214 Roo.bootstrap.DateField.head,
19215 Roo.bootstrap.DateField.content,
19216 Roo.bootstrap.DateField.footer
19223 cls: 'datepicker-years',
19227 cls: 'table-condensed',
19229 Roo.bootstrap.DateField.head,
19230 Roo.bootstrap.DateField.content,
19231 Roo.bootstrap.DateField.footer
19250 * @class Roo.bootstrap.TimeField
19251 * @extends Roo.bootstrap.Input
19252 * Bootstrap DateField class
19256 * Create a new TimeField
19257 * @param {Object} config The config object
19260 Roo.bootstrap.TimeField = function(config){
19261 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19265 * Fires when this field show.
19266 * @param {Roo.bootstrap.DateField} thisthis
19267 * @param {Mixed} date The date value
19272 * Fires when this field hide.
19273 * @param {Roo.bootstrap.DateField} this
19274 * @param {Mixed} date The date value
19279 * Fires when select a date.
19280 * @param {Roo.bootstrap.DateField} this
19281 * @param {Mixed} date The date value
19287 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19290 * @cfg {String} format
19291 * The default time format string which can be overriden for localization support. The format must be
19292 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19296 onRender: function(ct, position)
19299 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19301 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19303 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19305 this.pop = this.picker().select('>.datepicker-time',true).first();
19306 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19308 this.picker().on('mousedown', this.onMousedown, this);
19309 this.picker().on('click', this.onClick, this);
19311 this.picker().addClass('datepicker-dropdown');
19316 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19317 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19318 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19319 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19320 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19321 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19325 fireKey: function(e){
19326 if (!this.picker().isVisible()){
19327 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19333 e.preventDefault();
19341 this.onTogglePeriod();
19344 this.onIncrementMinutes();
19347 this.onDecrementMinutes();
19356 onClick: function(e) {
19357 e.stopPropagation();
19358 e.preventDefault();
19361 picker : function()
19363 return this.el.select('.datepicker', true).first();
19366 fillTime: function()
19368 var time = this.pop.select('tbody', true).first();
19370 time.dom.innerHTML = '';
19385 cls: 'hours-up glyphicon glyphicon-chevron-up'
19405 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19426 cls: 'timepicker-hour',
19441 cls: 'timepicker-minute',
19456 cls: 'btn btn-primary period',
19478 cls: 'hours-down glyphicon glyphicon-chevron-down'
19498 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19516 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19523 var hours = this.time.getHours();
19524 var minutes = this.time.getMinutes();
19537 hours = hours - 12;
19541 hours = '0' + hours;
19545 minutes = '0' + minutes;
19548 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19549 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19550 this.pop.select('button', true).first().dom.innerHTML = period;
19556 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19558 var cls = ['bottom'];
19560 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19567 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19572 this.picker().addClass(cls.join('-'));
19576 Roo.each(cls, function(c){
19578 _this.picker().setTop(_this.inputEl().getHeight());
19582 _this.picker().setTop(0 - _this.picker().getHeight());
19587 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19591 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19598 onFocus : function()
19600 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19604 onBlur : function()
19606 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19612 this.picker().show();
19617 this.fireEvent('show', this, this.date);
19622 this.picker().hide();
19625 this.fireEvent('hide', this, this.date);
19628 setTime : function()
19631 this.setValue(this.time.format(this.format));
19633 this.fireEvent('select', this, this.date);
19638 onMousedown: function(e){
19639 e.stopPropagation();
19640 e.preventDefault();
19643 onIncrementHours: function()
19645 Roo.log('onIncrementHours');
19646 this.time = this.time.add(Date.HOUR, 1);
19651 onDecrementHours: function()
19653 Roo.log('onDecrementHours');
19654 this.time = this.time.add(Date.HOUR, -1);
19658 onIncrementMinutes: function()
19660 Roo.log('onIncrementMinutes');
19661 this.time = this.time.add(Date.MINUTE, 1);
19665 onDecrementMinutes: function()
19667 Roo.log('onDecrementMinutes');
19668 this.time = this.time.add(Date.MINUTE, -1);
19672 onTogglePeriod: function()
19674 Roo.log('onTogglePeriod');
19675 this.time = this.time.add(Date.HOUR, 12);
19682 Roo.apply(Roo.bootstrap.TimeField, {
19712 cls: 'btn btn-info ok',
19724 Roo.apply(Roo.bootstrap.TimeField, {
19728 cls: 'datepicker dropdown-menu',
19732 cls: 'datepicker-time',
19736 cls: 'table-condensed',
19738 Roo.bootstrap.TimeField.content,
19739 Roo.bootstrap.TimeField.footer
19758 * @class Roo.bootstrap.MonthField
19759 * @extends Roo.bootstrap.Input
19760 * Bootstrap MonthField class
19762 * @cfg {String} language default en
19765 * Create a new MonthField
19766 * @param {Object} config The config object
19769 Roo.bootstrap.MonthField = function(config){
19770 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19775 * Fires when this field show.
19776 * @param {Roo.bootstrap.MonthField} this
19777 * @param {Mixed} date The date value
19782 * Fires when this field hide.
19783 * @param {Roo.bootstrap.MonthField} this
19784 * @param {Mixed} date The date value
19789 * Fires when select a date.
19790 * @param {Roo.bootstrap.MonthField} this
19791 * @param {String} oldvalue The old value
19792 * @param {String} newvalue The new value
19798 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19800 onRender: function(ct, position)
19803 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19805 this.language = this.language || 'en';
19806 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19807 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19809 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19810 this.isInline = false;
19811 this.isInput = true;
19812 this.component = this.el.select('.add-on', true).first() || false;
19813 this.component = (this.component && this.component.length === 0) ? false : this.component;
19814 this.hasInput = this.component && this.inputEL().length;
19816 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19818 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19820 this.picker().on('mousedown', this.onMousedown, this);
19821 this.picker().on('click', this.onClick, this);
19823 this.picker().addClass('datepicker-dropdown');
19825 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19826 v.setStyle('width', '189px');
19833 if(this.isInline) {
19839 setValue: function(v, suppressEvent)
19841 var o = this.getValue();
19843 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19847 if(suppressEvent !== true){
19848 this.fireEvent('select', this, o, v);
19853 getValue: function()
19858 onClick: function(e)
19860 e.stopPropagation();
19861 e.preventDefault();
19863 var target = e.getTarget();
19865 if(target.nodeName.toLowerCase() === 'i'){
19866 target = Roo.get(target).dom.parentNode;
19869 var nodeName = target.nodeName;
19870 var className = target.className;
19871 var html = target.innerHTML;
19873 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19877 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19879 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19885 picker : function()
19887 return this.pickerEl;
19890 fillMonths: function()
19893 var months = this.picker().select('>.datepicker-months td', true).first();
19895 months.dom.innerHTML = '';
19901 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19904 months.createChild(month);
19913 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19914 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19917 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19918 e.removeClass('active');
19920 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19921 e.addClass('active');
19928 if(this.isInline) {
19932 this.picker().removeClass(['bottom', 'top']);
19934 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19936 * place to the top of element!
19940 this.picker().addClass('top');
19941 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19946 this.picker().addClass('bottom');
19948 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19951 onFocus : function()
19953 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19957 onBlur : function()
19959 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19961 var d = this.inputEl().getValue();
19970 this.picker().show();
19971 this.picker().select('>.datepicker-months', true).first().show();
19975 this.fireEvent('show', this, this.date);
19980 if(this.isInline) {
19983 this.picker().hide();
19984 this.fireEvent('hide', this, this.date);
19988 onMousedown: function(e)
19990 e.stopPropagation();
19991 e.preventDefault();
19996 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20000 fireKey: function(e)
20002 if (!this.picker().isVisible()){
20003 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20014 e.preventDefault();
20018 dir = e.keyCode == 37 ? -1 : 1;
20020 this.vIndex = this.vIndex + dir;
20022 if(this.vIndex < 0){
20026 if(this.vIndex > 11){
20030 if(isNaN(this.vIndex)){
20034 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20040 dir = e.keyCode == 38 ? -1 : 1;
20042 this.vIndex = this.vIndex + dir * 4;
20044 if(this.vIndex < 0){
20048 if(this.vIndex > 11){
20052 if(isNaN(this.vIndex)){
20056 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20061 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20062 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20066 e.preventDefault();
20069 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20070 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20086 this.picker().remove();
20091 Roo.apply(Roo.bootstrap.MonthField, {
20110 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20111 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20116 Roo.apply(Roo.bootstrap.MonthField, {
20120 cls: 'datepicker dropdown-menu roo-dynamic',
20124 cls: 'datepicker-months',
20128 cls: 'table-condensed',
20130 Roo.bootstrap.DateField.content
20150 * @class Roo.bootstrap.CheckBox
20151 * @extends Roo.bootstrap.Input
20152 * Bootstrap CheckBox class
20154 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20155 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20156 * @cfg {String} boxLabel The text that appears beside the checkbox
20157 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20158 * @cfg {Boolean} checked initnal the element
20159 * @cfg {Boolean} inline inline the element (default false)
20160 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20161 * @cfg {String} tooltip label tooltip
20164 * Create a new CheckBox
20165 * @param {Object} config The config object
20168 Roo.bootstrap.CheckBox = function(config){
20169 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20174 * Fires when the element is checked or unchecked.
20175 * @param {Roo.bootstrap.CheckBox} this This input
20176 * @param {Boolean} checked The new checked value
20181 * Fires when the element is click.
20182 * @param {Roo.bootstrap.CheckBox} this This input
20189 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20191 inputType: 'checkbox',
20200 getAutoCreate : function()
20202 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20208 cfg.cls = 'form-group ' + this.inputType; //input-group
20211 cfg.cls += ' ' + this.inputType + '-inline';
20217 type : this.inputType,
20218 value : this.inputValue,
20219 cls : 'roo-' + this.inputType, //'form-box',
20220 placeholder : this.placeholder || ''
20224 if(this.inputType != 'radio'){
20228 cls : 'roo-hidden-value',
20229 value : this.checked ? this.inputValue : this.valueOff
20234 if (this.weight) { // Validity check?
20235 cfg.cls += " " + this.inputType + "-" + this.weight;
20238 if (this.disabled) {
20239 input.disabled=true;
20243 input.checked = this.checked;
20248 input.name = this.name;
20250 if(this.inputType != 'radio'){
20251 hidden.name = this.name;
20252 input.name = '_hidden_' + this.name;
20257 input.cls += ' input-' + this.size;
20262 ['xs','sm','md','lg'].map(function(size){
20263 if (settings[size]) {
20264 cfg.cls += ' col-' + size + '-' + settings[size];
20268 var inputblock = input;
20270 if (this.before || this.after) {
20273 cls : 'input-group',
20278 inputblock.cn.push({
20280 cls : 'input-group-addon',
20285 inputblock.cn.push(input);
20287 if(this.inputType != 'radio'){
20288 inputblock.cn.push(hidden);
20292 inputblock.cn.push({
20294 cls : 'input-group-addon',
20301 if (align ==='left' && this.fieldLabel.length) {
20302 // Roo.log("left and has label");
20307 cls : 'control-label',
20308 html : this.fieldLabel
20318 if(this.labelWidth > 12){
20319 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20322 if(this.labelWidth < 13 && this.labelmd == 0){
20323 this.labelmd = this.labelWidth;
20326 if(this.labellg > 0){
20327 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20328 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20331 if(this.labelmd > 0){
20332 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20333 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20336 if(this.labelsm > 0){
20337 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20338 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20341 if(this.labelxs > 0){
20342 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20343 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20346 } else if ( this.fieldLabel.length) {
20347 // Roo.log(" label");
20351 tag: this.boxLabel ? 'span' : 'label',
20353 cls: 'control-label box-input-label',
20354 //cls : 'input-group-addon',
20355 html : this.fieldLabel
20364 // Roo.log(" no label && no align");
20365 cfg.cn = [ inputblock ] ;
20371 var boxLabelCfg = {
20373 //'for': id, // box label is handled by onclick - so no for...
20375 html: this.boxLabel
20379 boxLabelCfg.tooltip = this.tooltip;
20382 cfg.cn.push(boxLabelCfg);
20385 if(this.inputType != 'radio'){
20386 cfg.cn.push(hidden);
20394 * return the real input element.
20396 inputEl: function ()
20398 return this.el.select('input.roo-' + this.inputType,true).first();
20400 hiddenEl: function ()
20402 return this.el.select('input.roo-hidden-value',true).first();
20405 labelEl: function()
20407 return this.el.select('label.control-label',true).first();
20409 /* depricated... */
20413 return this.labelEl();
20416 boxLabelEl: function()
20418 return this.el.select('label.box-label',true).first();
20421 initEvents : function()
20423 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20425 this.inputEl().on('click', this.onClick, this);
20427 if (this.boxLabel) {
20428 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20431 this.startValue = this.getValue();
20434 Roo.bootstrap.CheckBox.register(this);
20438 onClick : function(e)
20440 if(this.fireEvent('click', this, e) !== false){
20441 this.setChecked(!this.checked);
20446 setChecked : function(state,suppressEvent)
20448 this.startValue = this.getValue();
20450 if(this.inputType == 'radio'){
20452 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20453 e.dom.checked = false;
20456 this.inputEl().dom.checked = true;
20458 this.inputEl().dom.value = this.inputValue;
20460 if(suppressEvent !== true){
20461 this.fireEvent('check', this, true);
20469 this.checked = state;
20471 this.inputEl().dom.checked = state;
20474 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20476 if(suppressEvent !== true){
20477 this.fireEvent('check', this, state);
20483 getValue : function()
20485 if(this.inputType == 'radio'){
20486 return this.getGroupValue();
20489 return this.hiddenEl().dom.value;
20493 getGroupValue : function()
20495 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20499 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20502 setValue : function(v,suppressEvent)
20504 if(this.inputType == 'radio'){
20505 this.setGroupValue(v, suppressEvent);
20509 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20514 setGroupValue : function(v, suppressEvent)
20516 this.startValue = this.getValue();
20518 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20519 e.dom.checked = false;
20521 if(e.dom.value == v){
20522 e.dom.checked = true;
20526 if(suppressEvent !== true){
20527 this.fireEvent('check', this, true);
20535 validate : function()
20539 (this.inputType == 'radio' && this.validateRadio()) ||
20540 (this.inputType == 'checkbox' && this.validateCheckbox())
20546 this.markInvalid();
20550 validateRadio : function()
20552 if(this.allowBlank){
20558 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20559 if(!e.dom.checked){
20571 validateCheckbox : function()
20574 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20575 //return (this.getValue() == this.inputValue) ? true : false;
20578 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20586 for(var i in group){
20587 if(group[i].el.isVisible(true)){
20595 for(var i in group){
20600 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20607 * Mark this field as valid
20609 markValid : function()
20613 this.fireEvent('valid', this);
20615 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20618 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20625 if(this.inputType == 'radio'){
20626 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20627 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20628 e.findParent('.form-group', false, true).addClass(_this.validClass);
20635 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20636 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20640 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20646 for(var i in group){
20647 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20648 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20653 * Mark this field as invalid
20654 * @param {String} msg The validation message
20656 markInvalid : function(msg)
20658 if(this.allowBlank){
20664 this.fireEvent('invalid', this, msg);
20666 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20669 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20673 label.markInvalid();
20676 if(this.inputType == 'radio'){
20677 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20678 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20679 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20686 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20687 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20691 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20697 for(var i in group){
20698 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20699 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20704 clearInvalid : function()
20706 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20708 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20710 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20712 if (label && label.iconEl) {
20713 label.iconEl.removeClass(label.validClass);
20714 label.iconEl.removeClass(label.invalidClass);
20718 disable : function()
20720 if(this.inputType != 'radio'){
20721 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20728 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20729 _this.getActionEl().addClass(this.disabledClass);
20730 e.dom.disabled = true;
20734 this.disabled = true;
20735 this.fireEvent("disable", this);
20739 enable : function()
20741 if(this.inputType != 'radio'){
20742 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20749 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20750 _this.getActionEl().removeClass(this.disabledClass);
20751 e.dom.disabled = false;
20755 this.disabled = false;
20756 this.fireEvent("enable", this);
20760 setBoxLabel : function(v)
20765 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20771 Roo.apply(Roo.bootstrap.CheckBox, {
20776 * register a CheckBox Group
20777 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20779 register : function(checkbox)
20781 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20782 this.groups[checkbox.groupId] = {};
20785 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20789 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20793 * fetch a CheckBox Group based on the group ID
20794 * @param {string} the group ID
20795 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20797 get: function(groupId) {
20798 if (typeof(this.groups[groupId]) == 'undefined') {
20802 return this.groups[groupId] ;
20815 * @class Roo.bootstrap.Radio
20816 * @extends Roo.bootstrap.Component
20817 * Bootstrap Radio class
20818 * @cfg {String} boxLabel - the label associated
20819 * @cfg {String} value - the value of radio
20822 * Create a new Radio
20823 * @param {Object} config The config object
20825 Roo.bootstrap.Radio = function(config){
20826 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20830 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20836 getAutoCreate : function()
20840 cls : 'form-group radio',
20845 html : this.boxLabel
20853 initEvents : function()
20855 this.parent().register(this);
20857 this.el.on('click', this.onClick, this);
20861 onClick : function()
20863 this.setChecked(true);
20866 setChecked : function(state, suppressEvent)
20868 this.parent().setValue(this.value, suppressEvent);
20872 setBoxLabel : function(v)
20877 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20892 * @class Roo.bootstrap.SecurePass
20893 * @extends Roo.bootstrap.Input
20894 * Bootstrap SecurePass class
20898 * Create a new SecurePass
20899 * @param {Object} config The config object
20902 Roo.bootstrap.SecurePass = function (config) {
20903 // these go here, so the translation tool can replace them..
20905 PwdEmpty: "Please type a password, and then retype it to confirm.",
20906 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20907 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20908 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20909 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20910 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20911 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20912 TooWeak: "Your password is Too Weak."
20914 this.meterLabel = "Password strength:";
20915 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20916 this.meterClass = [
20917 "roo-password-meter-tooweak",
20918 "roo-password-meter-weak",
20919 "roo-password-meter-medium",
20920 "roo-password-meter-strong",
20921 "roo-password-meter-grey"
20926 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20929 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20931 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20933 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20934 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20935 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20936 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20937 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20938 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20939 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20949 * @cfg {String/Object} Label for the strength meter (defaults to
20950 * 'Password strength:')
20955 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20956 * ['Weak', 'Medium', 'Strong'])
20959 pwdStrengths: false,
20972 initEvents: function ()
20974 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20976 if (this.el.is('input[type=password]') && Roo.isSafari) {
20977 this.el.on('keydown', this.SafariOnKeyDown, this);
20980 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20983 onRender: function (ct, position)
20985 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20986 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20987 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20989 this.trigger.createChild({
20994 cls: 'roo-password-meter-grey col-xs-12',
20997 //width: this.meterWidth + 'px'
21001 cls: 'roo-password-meter-text'
21007 if (this.hideTrigger) {
21008 this.trigger.setDisplayed(false);
21010 this.setSize(this.width || '', this.height || '');
21013 onDestroy: function ()
21015 if (this.trigger) {
21016 this.trigger.removeAllListeners();
21017 this.trigger.remove();
21020 this.wrap.remove();
21022 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21025 checkStrength: function ()
21027 var pwd = this.inputEl().getValue();
21028 if (pwd == this._lastPwd) {
21033 if (this.ClientSideStrongPassword(pwd)) {
21035 } else if (this.ClientSideMediumPassword(pwd)) {
21037 } else if (this.ClientSideWeakPassword(pwd)) {
21043 Roo.log('strength1: ' + strength);
21045 //var pm = this.trigger.child('div/div/div').dom;
21046 var pm = this.trigger.child('div/div');
21047 pm.removeClass(this.meterClass);
21048 pm.addClass(this.meterClass[strength]);
21051 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21053 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21055 this._lastPwd = pwd;
21059 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21061 this._lastPwd = '';
21063 var pm = this.trigger.child('div/div');
21064 pm.removeClass(this.meterClass);
21065 pm.addClass('roo-password-meter-grey');
21068 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21071 this.inputEl().dom.type='password';
21074 validateValue: function (value)
21077 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21080 if (value.length == 0) {
21081 if (this.allowBlank) {
21082 this.clearInvalid();
21086 this.markInvalid(this.errors.PwdEmpty);
21087 this.errorMsg = this.errors.PwdEmpty;
21095 if ('[\x21-\x7e]*'.match(value)) {
21096 this.markInvalid(this.errors.PwdBadChar);
21097 this.errorMsg = this.errors.PwdBadChar;
21100 if (value.length < 6) {
21101 this.markInvalid(this.errors.PwdShort);
21102 this.errorMsg = this.errors.PwdShort;
21105 if (value.length > 16) {
21106 this.markInvalid(this.errors.PwdLong);
21107 this.errorMsg = this.errors.PwdLong;
21111 if (this.ClientSideStrongPassword(value)) {
21113 } else if (this.ClientSideMediumPassword(value)) {
21115 } else if (this.ClientSideWeakPassword(value)) {
21122 if (strength < 2) {
21123 //this.markInvalid(this.errors.TooWeak);
21124 this.errorMsg = this.errors.TooWeak;
21129 console.log('strength2: ' + strength);
21131 //var pm = this.trigger.child('div/div/div').dom;
21133 var pm = this.trigger.child('div/div');
21134 pm.removeClass(this.meterClass);
21135 pm.addClass(this.meterClass[strength]);
21137 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21139 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21141 this.errorMsg = '';
21145 CharacterSetChecks: function (type)
21148 this.fResult = false;
21151 isctype: function (character, type)
21154 case this.kCapitalLetter:
21155 if (character >= 'A' && character <= 'Z') {
21160 case this.kSmallLetter:
21161 if (character >= 'a' && character <= 'z') {
21167 if (character >= '0' && character <= '9') {
21172 case this.kPunctuation:
21173 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21184 IsLongEnough: function (pwd, size)
21186 return !(pwd == null || isNaN(size) || pwd.length < size);
21189 SpansEnoughCharacterSets: function (word, nb)
21191 if (!this.IsLongEnough(word, nb))
21196 var characterSetChecks = new Array(
21197 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21198 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21201 for (var index = 0; index < word.length; ++index) {
21202 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21203 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21204 characterSetChecks[nCharSet].fResult = true;
21211 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21212 if (characterSetChecks[nCharSet].fResult) {
21217 if (nCharSets < nb) {
21223 ClientSideStrongPassword: function (pwd)
21225 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21228 ClientSideMediumPassword: function (pwd)
21230 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21233 ClientSideWeakPassword: function (pwd)
21235 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21238 })//<script type="text/javascript">
21241 * Based Ext JS Library 1.1.1
21242 * Copyright(c) 2006-2007, Ext JS, LLC.
21248 * @class Roo.HtmlEditorCore
21249 * @extends Roo.Component
21250 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21252 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21255 Roo.HtmlEditorCore = function(config){
21258 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21263 * @event initialize
21264 * Fires when the editor is fully initialized (including the iframe)
21265 * @param {Roo.HtmlEditorCore} this
21270 * Fires when the editor is first receives the focus. Any insertion must wait
21271 * until after this event.
21272 * @param {Roo.HtmlEditorCore} this
21276 * @event beforesync
21277 * Fires before the textarea is updated with content from the editor iframe. Return false
21278 * to cancel the sync.
21279 * @param {Roo.HtmlEditorCore} this
21280 * @param {String} html
21284 * @event beforepush
21285 * Fires before the iframe editor is updated with content from the textarea. Return false
21286 * to cancel the push.
21287 * @param {Roo.HtmlEditorCore} this
21288 * @param {String} html
21293 * Fires when the textarea is updated with content from the editor iframe.
21294 * @param {Roo.HtmlEditorCore} this
21295 * @param {String} html
21300 * Fires when the iframe editor is updated with content from the textarea.
21301 * @param {Roo.HtmlEditorCore} this
21302 * @param {String} html
21307 * @event editorevent
21308 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21309 * @param {Roo.HtmlEditorCore} this
21315 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21317 // defaults : white / black...
21318 this.applyBlacklists();
21325 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21329 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21335 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21340 * @cfg {Number} height (in pixels)
21344 * @cfg {Number} width (in pixels)
21349 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21352 stylesheets: false,
21357 // private properties
21358 validationEvent : false,
21360 initialized : false,
21362 sourceEditMode : false,
21363 onFocus : Roo.emptyFn,
21365 hideMode:'offsets',
21369 // blacklist + whitelisted elements..
21376 * Protected method that will not generally be called directly. It
21377 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21378 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21380 getDocMarkup : function(){
21384 // inherit styels from page...??
21385 if (this.stylesheets === false) {
21387 Roo.get(document.head).select('style').each(function(node) {
21388 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21391 Roo.get(document.head).select('link').each(function(node) {
21392 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21395 } else if (!this.stylesheets.length) {
21397 st = '<style type="text/css">' +
21398 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21401 st = '<style type="text/css">' +
21406 st += '<style type="text/css">' +
21407 'IMG { cursor: pointer } ' +
21410 var cls = 'roo-htmleditor-body';
21412 if(this.bodyCls.length){
21413 cls += ' ' + this.bodyCls;
21416 return '<html><head>' + st +
21417 //<style type="text/css">' +
21418 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21420 ' </head><body class="' + cls + '"></body></html>';
21424 onRender : function(ct, position)
21427 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21428 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21431 this.el.dom.style.border = '0 none';
21432 this.el.dom.setAttribute('tabIndex', -1);
21433 this.el.addClass('x-hidden hide');
21437 if(Roo.isIE){ // fix IE 1px bogus margin
21438 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21442 this.frameId = Roo.id();
21446 var iframe = this.owner.wrap.createChild({
21448 cls: 'form-control', // bootstrap..
21450 name: this.frameId,
21451 frameBorder : 'no',
21452 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21457 this.iframe = iframe.dom;
21459 this.assignDocWin();
21461 this.doc.designMode = 'on';
21464 this.doc.write(this.getDocMarkup());
21468 var task = { // must defer to wait for browser to be ready
21470 //console.log("run task?" + this.doc.readyState);
21471 this.assignDocWin();
21472 if(this.doc.body || this.doc.readyState == 'complete'){
21474 this.doc.designMode="on";
21478 Roo.TaskMgr.stop(task);
21479 this.initEditor.defer(10, this);
21486 Roo.TaskMgr.start(task);
21491 onResize : function(w, h)
21493 Roo.log('resize: ' +w + ',' + h );
21494 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21498 if(typeof w == 'number'){
21500 this.iframe.style.width = w + 'px';
21502 if(typeof h == 'number'){
21504 this.iframe.style.height = h + 'px';
21506 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21513 * Toggles the editor between standard and source edit mode.
21514 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21516 toggleSourceEdit : function(sourceEditMode){
21518 this.sourceEditMode = sourceEditMode === true;
21520 if(this.sourceEditMode){
21522 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21525 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21526 //this.iframe.className = '';
21529 //this.setSize(this.owner.wrap.getSize());
21530 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21537 * Protected method that will not generally be called directly. If you need/want
21538 * custom HTML cleanup, this is the method you should override.
21539 * @param {String} html The HTML to be cleaned
21540 * return {String} The cleaned HTML
21542 cleanHtml : function(html){
21543 html = String(html);
21544 if(html.length > 5){
21545 if(Roo.isSafari){ // strip safari nonsense
21546 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21549 if(html == ' '){
21556 * HTML Editor -> Textarea
21557 * Protected method that will not generally be called directly. Syncs the contents
21558 * of the editor iframe with the textarea.
21560 syncValue : function(){
21561 if(this.initialized){
21562 var bd = (this.doc.body || this.doc.documentElement);
21563 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21564 var html = bd.innerHTML;
21566 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21567 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21569 html = '<div style="'+m[0]+'">' + html + '</div>';
21572 html = this.cleanHtml(html);
21573 // fix up the special chars.. normaly like back quotes in word...
21574 // however we do not want to do this with chinese..
21575 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21576 var cc = b.charCodeAt();
21578 (cc >= 0x4E00 && cc < 0xA000 ) ||
21579 (cc >= 0x3400 && cc < 0x4E00 ) ||
21580 (cc >= 0xf900 && cc < 0xfb00 )
21586 if(this.owner.fireEvent('beforesync', this, html) !== false){
21587 this.el.dom.value = html;
21588 this.owner.fireEvent('sync', this, html);
21594 * Protected method that will not generally be called directly. Pushes the value of the textarea
21595 * into the iframe editor.
21597 pushValue : function(){
21598 if(this.initialized){
21599 var v = this.el.dom.value.trim();
21601 // if(v.length < 1){
21605 if(this.owner.fireEvent('beforepush', this, v) !== false){
21606 var d = (this.doc.body || this.doc.documentElement);
21608 this.cleanUpPaste();
21609 this.el.dom.value = d.innerHTML;
21610 this.owner.fireEvent('push', this, v);
21616 deferFocus : function(){
21617 this.focus.defer(10, this);
21621 focus : function(){
21622 if(this.win && !this.sourceEditMode){
21629 assignDocWin: function()
21631 var iframe = this.iframe;
21634 this.doc = iframe.contentWindow.document;
21635 this.win = iframe.contentWindow;
21637 // if (!Roo.get(this.frameId)) {
21640 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21641 // this.win = Roo.get(this.frameId).dom.contentWindow;
21643 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21647 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21648 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21653 initEditor : function(){
21654 //console.log("INIT EDITOR");
21655 this.assignDocWin();
21659 this.doc.designMode="on";
21661 this.doc.write(this.getDocMarkup());
21664 var dbody = (this.doc.body || this.doc.documentElement);
21665 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21666 // this copies styles from the containing element into thsi one..
21667 // not sure why we need all of this..
21668 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21670 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21671 //ss['background-attachment'] = 'fixed'; // w3c
21672 dbody.bgProperties = 'fixed'; // ie
21673 //Roo.DomHelper.applyStyles(dbody, ss);
21674 Roo.EventManager.on(this.doc, {
21675 //'mousedown': this.onEditorEvent,
21676 'mouseup': this.onEditorEvent,
21677 'dblclick': this.onEditorEvent,
21678 'click': this.onEditorEvent,
21679 'keyup': this.onEditorEvent,
21684 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21686 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21687 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21689 this.initialized = true;
21691 this.owner.fireEvent('initialize', this);
21696 onDestroy : function(){
21702 //for (var i =0; i < this.toolbars.length;i++) {
21703 // // fixme - ask toolbars for heights?
21704 // this.toolbars[i].onDestroy();
21707 //this.wrap.dom.innerHTML = '';
21708 //this.wrap.remove();
21713 onFirstFocus : function(){
21715 this.assignDocWin();
21718 this.activated = true;
21721 if(Roo.isGecko){ // prevent silly gecko errors
21723 var s = this.win.getSelection();
21724 if(!s.focusNode || s.focusNode.nodeType != 3){
21725 var r = s.getRangeAt(0);
21726 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21731 this.execCmd('useCSS', true);
21732 this.execCmd('styleWithCSS', false);
21735 this.owner.fireEvent('activate', this);
21739 adjustFont: function(btn){
21740 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21741 //if(Roo.isSafari){ // safari
21744 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21745 if(Roo.isSafari){ // safari
21746 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21747 v = (v < 10) ? 10 : v;
21748 v = (v > 48) ? 48 : v;
21749 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21754 v = Math.max(1, v+adjust);
21756 this.execCmd('FontSize', v );
21759 onEditorEvent : function(e)
21761 this.owner.fireEvent('editorevent', this, e);
21762 // this.updateToolbar();
21763 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21766 insertTag : function(tg)
21768 // could be a bit smarter... -> wrap the current selected tRoo..
21769 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21771 range = this.createRange(this.getSelection());
21772 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21773 wrappingNode.appendChild(range.extractContents());
21774 range.insertNode(wrappingNode);
21781 this.execCmd("formatblock", tg);
21785 insertText : function(txt)
21789 var range = this.createRange();
21790 range.deleteContents();
21791 //alert(Sender.getAttribute('label'));
21793 range.insertNode(this.doc.createTextNode(txt));
21799 * Executes a Midas editor command on the editor document and performs necessary focus and
21800 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21801 * @param {String} cmd The Midas command
21802 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21804 relayCmd : function(cmd, value){
21806 this.execCmd(cmd, value);
21807 this.owner.fireEvent('editorevent', this);
21808 //this.updateToolbar();
21809 this.owner.deferFocus();
21813 * Executes a Midas editor command directly on the editor document.
21814 * For visual commands, you should use {@link #relayCmd} instead.
21815 * <b>This should only be called after the editor is initialized.</b>
21816 * @param {String} cmd The Midas command
21817 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21819 execCmd : function(cmd, value){
21820 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21827 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21829 * @param {String} text | dom node..
21831 insertAtCursor : function(text)
21834 if(!this.activated){
21840 var r = this.doc.selection.createRange();
21851 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21855 // from jquery ui (MIT licenced)
21857 var win = this.win;
21859 if (win.getSelection && win.getSelection().getRangeAt) {
21860 range = win.getSelection().getRangeAt(0);
21861 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21862 range.insertNode(node);
21863 } else if (win.document.selection && win.document.selection.createRange) {
21864 // no firefox support
21865 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21866 win.document.selection.createRange().pasteHTML(txt);
21868 // no firefox support
21869 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21870 this.execCmd('InsertHTML', txt);
21879 mozKeyPress : function(e){
21881 var c = e.getCharCode(), cmd;
21884 c = String.fromCharCode(c).toLowerCase();
21898 this.cleanUpPaste.defer(100, this);
21906 e.preventDefault();
21914 fixKeys : function(){ // load time branching for fastest keydown performance
21916 return function(e){
21917 var k = e.getKey(), r;
21920 r = this.doc.selection.createRange();
21923 r.pasteHTML('    ');
21930 r = this.doc.selection.createRange();
21932 var target = r.parentElement();
21933 if(!target || target.tagName.toLowerCase() != 'li'){
21935 r.pasteHTML('<br />');
21941 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21942 this.cleanUpPaste.defer(100, this);
21948 }else if(Roo.isOpera){
21949 return function(e){
21950 var k = e.getKey();
21954 this.execCmd('InsertHTML','    ');
21957 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21958 this.cleanUpPaste.defer(100, this);
21963 }else if(Roo.isSafari){
21964 return function(e){
21965 var k = e.getKey();
21969 this.execCmd('InsertText','\t');
21973 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21974 this.cleanUpPaste.defer(100, this);
21982 getAllAncestors: function()
21984 var p = this.getSelectedNode();
21987 a.push(p); // push blank onto stack..
21988 p = this.getParentElement();
21992 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21996 a.push(this.doc.body);
22000 lastSelNode : false,
22003 getSelection : function()
22005 this.assignDocWin();
22006 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22009 getSelectedNode: function()
22011 // this may only work on Gecko!!!
22013 // should we cache this!!!!
22018 var range = this.createRange(this.getSelection()).cloneRange();
22021 var parent = range.parentElement();
22023 var testRange = range.duplicate();
22024 testRange.moveToElementText(parent);
22025 if (testRange.inRange(range)) {
22028 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22031 parent = parent.parentElement;
22036 // is ancestor a text element.
22037 var ac = range.commonAncestorContainer;
22038 if (ac.nodeType == 3) {
22039 ac = ac.parentNode;
22042 var ar = ac.childNodes;
22045 var other_nodes = [];
22046 var has_other_nodes = false;
22047 for (var i=0;i<ar.length;i++) {
22048 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22051 // fullly contained node.
22053 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22058 // probably selected..
22059 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22060 other_nodes.push(ar[i]);
22064 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22069 has_other_nodes = true;
22071 if (!nodes.length && other_nodes.length) {
22072 nodes= other_nodes;
22074 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22080 createRange: function(sel)
22082 // this has strange effects when using with
22083 // top toolbar - not sure if it's a great idea.
22084 //this.editor.contentWindow.focus();
22085 if (typeof sel != "undefined") {
22087 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22089 return this.doc.createRange();
22092 return this.doc.createRange();
22095 getParentElement: function()
22098 this.assignDocWin();
22099 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22101 var range = this.createRange(sel);
22104 var p = range.commonAncestorContainer;
22105 while (p.nodeType == 3) { // text node
22116 * Range intersection.. the hard stuff...
22120 * [ -- selected range --- ]
22124 * if end is before start or hits it. fail.
22125 * if start is after end or hits it fail.
22127 * if either hits (but other is outside. - then it's not
22133 // @see http://www.thismuchiknow.co.uk/?p=64.
22134 rangeIntersectsNode : function(range, node)
22136 var nodeRange = node.ownerDocument.createRange();
22138 nodeRange.selectNode(node);
22140 nodeRange.selectNodeContents(node);
22143 var rangeStartRange = range.cloneRange();
22144 rangeStartRange.collapse(true);
22146 var rangeEndRange = range.cloneRange();
22147 rangeEndRange.collapse(false);
22149 var nodeStartRange = nodeRange.cloneRange();
22150 nodeStartRange.collapse(true);
22152 var nodeEndRange = nodeRange.cloneRange();
22153 nodeEndRange.collapse(false);
22155 return rangeStartRange.compareBoundaryPoints(
22156 Range.START_TO_START, nodeEndRange) == -1 &&
22157 rangeEndRange.compareBoundaryPoints(
22158 Range.START_TO_START, nodeStartRange) == 1;
22162 rangeCompareNode : function(range, node)
22164 var nodeRange = node.ownerDocument.createRange();
22166 nodeRange.selectNode(node);
22168 nodeRange.selectNodeContents(node);
22172 range.collapse(true);
22174 nodeRange.collapse(true);
22176 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22177 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22179 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22181 var nodeIsBefore = ss == 1;
22182 var nodeIsAfter = ee == -1;
22184 if (nodeIsBefore && nodeIsAfter) {
22187 if (!nodeIsBefore && nodeIsAfter) {
22188 return 1; //right trailed.
22191 if (nodeIsBefore && !nodeIsAfter) {
22192 return 2; // left trailed.
22198 // private? - in a new class?
22199 cleanUpPaste : function()
22201 // cleans up the whole document..
22202 Roo.log('cleanuppaste');
22204 this.cleanUpChildren(this.doc.body);
22205 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22206 if (clean != this.doc.body.innerHTML) {
22207 this.doc.body.innerHTML = clean;
22212 cleanWordChars : function(input) {// change the chars to hex code
22213 var he = Roo.HtmlEditorCore;
22215 var output = input;
22216 Roo.each(he.swapCodes, function(sw) {
22217 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22219 output = output.replace(swapper, sw[1]);
22226 cleanUpChildren : function (n)
22228 if (!n.childNodes.length) {
22231 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22232 this.cleanUpChild(n.childNodes[i]);
22239 cleanUpChild : function (node)
22242 //console.log(node);
22243 if (node.nodeName == "#text") {
22244 // clean up silly Windows -- stuff?
22247 if (node.nodeName == "#comment") {
22248 node.parentNode.removeChild(node);
22249 // clean up silly Windows -- stuff?
22252 var lcname = node.tagName.toLowerCase();
22253 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22254 // whitelist of tags..
22256 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22258 node.parentNode.removeChild(node);
22263 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22265 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22266 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22268 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22269 // remove_keep_children = true;
22272 if (remove_keep_children) {
22273 this.cleanUpChildren(node);
22274 // inserts everything just before this node...
22275 while (node.childNodes.length) {
22276 var cn = node.childNodes[0];
22277 node.removeChild(cn);
22278 node.parentNode.insertBefore(cn, node);
22280 node.parentNode.removeChild(node);
22284 if (!node.attributes || !node.attributes.length) {
22285 this.cleanUpChildren(node);
22289 function cleanAttr(n,v)
22292 if (v.match(/^\./) || v.match(/^\//)) {
22295 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22298 if (v.match(/^#/)) {
22301 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22302 node.removeAttribute(n);
22306 var cwhite = this.cwhite;
22307 var cblack = this.cblack;
22309 function cleanStyle(n,v)
22311 if (v.match(/expression/)) { //XSS?? should we even bother..
22312 node.removeAttribute(n);
22316 var parts = v.split(/;/);
22319 Roo.each(parts, function(p) {
22320 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22324 var l = p.split(':').shift().replace(/\s+/g,'');
22325 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22327 if ( cwhite.length && cblack.indexOf(l) > -1) {
22328 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22329 //node.removeAttribute(n);
22333 // only allow 'c whitelisted system attributes'
22334 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22335 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22336 //node.removeAttribute(n);
22346 if (clean.length) {
22347 node.setAttribute(n, clean.join(';'));
22349 node.removeAttribute(n);
22355 for (var i = node.attributes.length-1; i > -1 ; i--) {
22356 var a = node.attributes[i];
22359 if (a.name.toLowerCase().substr(0,2)=='on') {
22360 node.removeAttribute(a.name);
22363 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22364 node.removeAttribute(a.name);
22367 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22368 cleanAttr(a.name,a.value); // fixme..
22371 if (a.name == 'style') {
22372 cleanStyle(a.name,a.value);
22375 /// clean up MS crap..
22376 // tecnically this should be a list of valid class'es..
22379 if (a.name == 'class') {
22380 if (a.value.match(/^Mso/)) {
22381 node.className = '';
22384 if (a.value.match(/^body$/)) {
22385 node.className = '';
22396 this.cleanUpChildren(node);
22402 * Clean up MS wordisms...
22404 cleanWord : function(node)
22409 this.cleanWord(this.doc.body);
22412 if (node.nodeName == "#text") {
22413 // clean up silly Windows -- stuff?
22416 if (node.nodeName == "#comment") {
22417 node.parentNode.removeChild(node);
22418 // clean up silly Windows -- stuff?
22422 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22423 node.parentNode.removeChild(node);
22427 // remove - but keep children..
22428 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22429 while (node.childNodes.length) {
22430 var cn = node.childNodes[0];
22431 node.removeChild(cn);
22432 node.parentNode.insertBefore(cn, node);
22434 node.parentNode.removeChild(node);
22435 this.iterateChildren(node, this.cleanWord);
22439 if (node.className.length) {
22441 var cn = node.className.split(/\W+/);
22443 Roo.each(cn, function(cls) {
22444 if (cls.match(/Mso[a-zA-Z]+/)) {
22449 node.className = cna.length ? cna.join(' ') : '';
22451 node.removeAttribute("class");
22455 if (node.hasAttribute("lang")) {
22456 node.removeAttribute("lang");
22459 if (node.hasAttribute("style")) {
22461 var styles = node.getAttribute("style").split(";");
22463 Roo.each(styles, function(s) {
22464 if (!s.match(/:/)) {
22467 var kv = s.split(":");
22468 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22471 // what ever is left... we allow.
22474 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22475 if (!nstyle.length) {
22476 node.removeAttribute('style');
22479 this.iterateChildren(node, this.cleanWord);
22485 * iterateChildren of a Node, calling fn each time, using this as the scole..
22486 * @param {DomNode} node node to iterate children of.
22487 * @param {Function} fn method of this class to call on each item.
22489 iterateChildren : function(node, fn)
22491 if (!node.childNodes.length) {
22494 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22495 fn.call(this, node.childNodes[i])
22501 * cleanTableWidths.
22503 * Quite often pasting from word etc.. results in tables with column and widths.
22504 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22507 cleanTableWidths : function(node)
22512 this.cleanTableWidths(this.doc.body);
22517 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22520 Roo.log(node.tagName);
22521 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22522 this.iterateChildren(node, this.cleanTableWidths);
22525 if (node.hasAttribute('width')) {
22526 node.removeAttribute('width');
22530 if (node.hasAttribute("style")) {
22533 var styles = node.getAttribute("style").split(";");
22535 Roo.each(styles, function(s) {
22536 if (!s.match(/:/)) {
22539 var kv = s.split(":");
22540 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22543 // what ever is left... we allow.
22546 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22547 if (!nstyle.length) {
22548 node.removeAttribute('style');
22552 this.iterateChildren(node, this.cleanTableWidths);
22560 domToHTML : function(currentElement, depth, nopadtext) {
22562 depth = depth || 0;
22563 nopadtext = nopadtext || false;
22565 if (!currentElement) {
22566 return this.domToHTML(this.doc.body);
22569 //Roo.log(currentElement);
22571 var allText = false;
22572 var nodeName = currentElement.nodeName;
22573 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22575 if (nodeName == '#text') {
22577 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22582 if (nodeName != 'BODY') {
22585 // Prints the node tagName, such as <A>, <IMG>, etc
22588 for(i = 0; i < currentElement.attributes.length;i++) {
22590 var aname = currentElement.attributes.item(i).name;
22591 if (!currentElement.attributes.item(i).value.length) {
22594 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22597 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22606 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22609 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22614 // Traverse the tree
22616 var currentElementChild = currentElement.childNodes.item(i);
22617 var allText = true;
22618 var innerHTML = '';
22620 while (currentElementChild) {
22621 // Formatting code (indent the tree so it looks nice on the screen)
22622 var nopad = nopadtext;
22623 if (lastnode == 'SPAN') {
22627 if (currentElementChild.nodeName == '#text') {
22628 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22629 toadd = nopadtext ? toadd : toadd.trim();
22630 if (!nopad && toadd.length > 80) {
22631 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22633 innerHTML += toadd;
22636 currentElementChild = currentElement.childNodes.item(i);
22642 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22644 // Recursively traverse the tree structure of the child node
22645 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22646 lastnode = currentElementChild.nodeName;
22648 currentElementChild=currentElement.childNodes.item(i);
22654 // The remaining code is mostly for formatting the tree
22655 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22660 ret+= "</"+tagName+">";
22666 applyBlacklists : function()
22668 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22669 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22673 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22674 if (b.indexOf(tag) > -1) {
22677 this.white.push(tag);
22681 Roo.each(w, function(tag) {
22682 if (b.indexOf(tag) > -1) {
22685 if (this.white.indexOf(tag) > -1) {
22688 this.white.push(tag);
22693 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22694 if (w.indexOf(tag) > -1) {
22697 this.black.push(tag);
22701 Roo.each(b, function(tag) {
22702 if (w.indexOf(tag) > -1) {
22705 if (this.black.indexOf(tag) > -1) {
22708 this.black.push(tag);
22713 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22714 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22718 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22719 if (b.indexOf(tag) > -1) {
22722 this.cwhite.push(tag);
22726 Roo.each(w, function(tag) {
22727 if (b.indexOf(tag) > -1) {
22730 if (this.cwhite.indexOf(tag) > -1) {
22733 this.cwhite.push(tag);
22738 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22739 if (w.indexOf(tag) > -1) {
22742 this.cblack.push(tag);
22746 Roo.each(b, function(tag) {
22747 if (w.indexOf(tag) > -1) {
22750 if (this.cblack.indexOf(tag) > -1) {
22753 this.cblack.push(tag);
22758 setStylesheets : function(stylesheets)
22760 if(typeof(stylesheets) == 'string'){
22761 Roo.get(this.iframe.contentDocument.head).createChild({
22763 rel : 'stylesheet',
22772 Roo.each(stylesheets, function(s) {
22777 Roo.get(_this.iframe.contentDocument.head).createChild({
22779 rel : 'stylesheet',
22788 removeStylesheets : function()
22792 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22797 setStyle : function(style)
22799 Roo.get(this.iframe.contentDocument.head).createChild({
22808 // hide stuff that is not compatible
22822 * @event specialkey
22826 * @cfg {String} fieldClass @hide
22829 * @cfg {String} focusClass @hide
22832 * @cfg {String} autoCreate @hide
22835 * @cfg {String} inputType @hide
22838 * @cfg {String} invalidClass @hide
22841 * @cfg {String} invalidText @hide
22844 * @cfg {String} msgFx @hide
22847 * @cfg {String} validateOnBlur @hide
22851 Roo.HtmlEditorCore.white = [
22852 'area', 'br', 'img', 'input', 'hr', 'wbr',
22854 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22855 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22856 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22857 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22858 'table', 'ul', 'xmp',
22860 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22863 'dir', 'menu', 'ol', 'ul', 'dl',
22869 Roo.HtmlEditorCore.black = [
22870 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22872 'base', 'basefont', 'bgsound', 'blink', 'body',
22873 'frame', 'frameset', 'head', 'html', 'ilayer',
22874 'iframe', 'layer', 'link', 'meta', 'object',
22875 'script', 'style' ,'title', 'xml' // clean later..
22877 Roo.HtmlEditorCore.clean = [
22878 'script', 'style', 'title', 'xml'
22880 Roo.HtmlEditorCore.remove = [
22885 Roo.HtmlEditorCore.ablack = [
22889 Roo.HtmlEditorCore.aclean = [
22890 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22894 Roo.HtmlEditorCore.pwhite= [
22895 'http', 'https', 'mailto'
22898 // white listed style attributes.
22899 Roo.HtmlEditorCore.cwhite= [
22900 // 'text-align', /// default is to allow most things..
22906 // black listed style attributes.
22907 Roo.HtmlEditorCore.cblack= [
22908 // 'font-size' -- this can be set by the project
22912 Roo.HtmlEditorCore.swapCodes =[
22931 * @class Roo.bootstrap.HtmlEditor
22932 * @extends Roo.bootstrap.TextArea
22933 * Bootstrap HtmlEditor class
22936 * Create a new HtmlEditor
22937 * @param {Object} config The config object
22940 Roo.bootstrap.HtmlEditor = function(config){
22941 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22942 if (!this.toolbars) {
22943 this.toolbars = [];
22946 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22949 * @event initialize
22950 * Fires when the editor is fully initialized (including the iframe)
22951 * @param {HtmlEditor} this
22956 * Fires when the editor is first receives the focus. Any insertion must wait
22957 * until after this event.
22958 * @param {HtmlEditor} this
22962 * @event beforesync
22963 * Fires before the textarea is updated with content from the editor iframe. Return false
22964 * to cancel the sync.
22965 * @param {HtmlEditor} this
22966 * @param {String} html
22970 * @event beforepush
22971 * Fires before the iframe editor is updated with content from the textarea. Return false
22972 * to cancel the push.
22973 * @param {HtmlEditor} this
22974 * @param {String} html
22979 * Fires when the textarea is updated with content from the editor iframe.
22980 * @param {HtmlEditor} this
22981 * @param {String} html
22986 * Fires when the iframe editor is updated with content from the textarea.
22987 * @param {HtmlEditor} this
22988 * @param {String} html
22992 * @event editmodechange
22993 * Fires when the editor switches edit modes
22994 * @param {HtmlEditor} this
22995 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22997 editmodechange: true,
22999 * @event editorevent
23000 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23001 * @param {HtmlEditor} this
23005 * @event firstfocus
23006 * Fires when on first focus - needed by toolbars..
23007 * @param {HtmlEditor} this
23012 * Auto save the htmlEditor value as a file into Events
23013 * @param {HtmlEditor} this
23017 * @event savedpreview
23018 * preview the saved version of htmlEditor
23019 * @param {HtmlEditor} this
23026 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23030 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23035 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23040 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23045 * @cfg {Number} height (in pixels)
23049 * @cfg {Number} width (in pixels)
23054 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23057 stylesheets: false,
23062 // private properties
23063 validationEvent : false,
23065 initialized : false,
23068 onFocus : Roo.emptyFn,
23070 hideMode:'offsets',
23072 tbContainer : false,
23076 toolbarContainer :function() {
23077 return this.wrap.select('.x-html-editor-tb',true).first();
23081 * Protected method that will not generally be called directly. It
23082 * is called when the editor creates its toolbar. Override this method if you need to
23083 * add custom toolbar buttons.
23084 * @param {HtmlEditor} editor
23086 createToolbar : function(){
23087 Roo.log('renewing');
23088 Roo.log("create toolbars");
23090 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23091 this.toolbars[0].render(this.toolbarContainer());
23095 // if (!editor.toolbars || !editor.toolbars.length) {
23096 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23099 // for (var i =0 ; i < editor.toolbars.length;i++) {
23100 // editor.toolbars[i] = Roo.factory(
23101 // typeof(editor.toolbars[i]) == 'string' ?
23102 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23103 // Roo.bootstrap.HtmlEditor);
23104 // editor.toolbars[i].init(editor);
23110 onRender : function(ct, position)
23112 // Roo.log("Call onRender: " + this.xtype);
23114 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23116 this.wrap = this.inputEl().wrap({
23117 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23120 this.editorcore.onRender(ct, position);
23122 if (this.resizable) {
23123 this.resizeEl = new Roo.Resizable(this.wrap, {
23127 minHeight : this.height,
23128 height: this.height,
23129 handles : this.resizable,
23132 resize : function(r, w, h) {
23133 _t.onResize(w,h); // -something
23139 this.createToolbar(this);
23142 if(!this.width && this.resizable){
23143 this.setSize(this.wrap.getSize());
23145 if (this.resizeEl) {
23146 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23147 // should trigger onReize..
23153 onResize : function(w, h)
23155 Roo.log('resize: ' +w + ',' + h );
23156 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23160 if(this.inputEl() ){
23161 if(typeof w == 'number'){
23162 var aw = w - this.wrap.getFrameWidth('lr');
23163 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23166 if(typeof h == 'number'){
23167 var tbh = -11; // fixme it needs to tool bar size!
23168 for (var i =0; i < this.toolbars.length;i++) {
23169 // fixme - ask toolbars for heights?
23170 tbh += this.toolbars[i].el.getHeight();
23171 //if (this.toolbars[i].footer) {
23172 // tbh += this.toolbars[i].footer.el.getHeight();
23180 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23181 ah -= 5; // knock a few pixes off for look..
23182 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23186 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23187 this.editorcore.onResize(ew,eh);
23192 * Toggles the editor between standard and source edit mode.
23193 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23195 toggleSourceEdit : function(sourceEditMode)
23197 this.editorcore.toggleSourceEdit(sourceEditMode);
23199 if(this.editorcore.sourceEditMode){
23200 Roo.log('editor - showing textarea');
23203 // Roo.log(this.syncValue());
23205 this.inputEl().removeClass(['hide', 'x-hidden']);
23206 this.inputEl().dom.removeAttribute('tabIndex');
23207 this.inputEl().focus();
23209 Roo.log('editor - hiding textarea');
23211 // Roo.log(this.pushValue());
23214 this.inputEl().addClass(['hide', 'x-hidden']);
23215 this.inputEl().dom.setAttribute('tabIndex', -1);
23216 //this.deferFocus();
23219 if(this.resizable){
23220 this.setSize(this.wrap.getSize());
23223 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23226 // private (for BoxComponent)
23227 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23229 // private (for BoxComponent)
23230 getResizeEl : function(){
23234 // private (for BoxComponent)
23235 getPositionEl : function(){
23240 initEvents : function(){
23241 this.originalValue = this.getValue();
23245 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23248 // markInvalid : Roo.emptyFn,
23250 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23253 // clearInvalid : Roo.emptyFn,
23255 setValue : function(v){
23256 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23257 this.editorcore.pushValue();
23262 deferFocus : function(){
23263 this.focus.defer(10, this);
23267 focus : function(){
23268 this.editorcore.focus();
23274 onDestroy : function(){
23280 for (var i =0; i < this.toolbars.length;i++) {
23281 // fixme - ask toolbars for heights?
23282 this.toolbars[i].onDestroy();
23285 this.wrap.dom.innerHTML = '';
23286 this.wrap.remove();
23291 onFirstFocus : function(){
23292 //Roo.log("onFirstFocus");
23293 this.editorcore.onFirstFocus();
23294 for (var i =0; i < this.toolbars.length;i++) {
23295 this.toolbars[i].onFirstFocus();
23301 syncValue : function()
23303 this.editorcore.syncValue();
23306 pushValue : function()
23308 this.editorcore.pushValue();
23312 // hide stuff that is not compatible
23326 * @event specialkey
23330 * @cfg {String} fieldClass @hide
23333 * @cfg {String} focusClass @hide
23336 * @cfg {String} autoCreate @hide
23339 * @cfg {String} inputType @hide
23342 * @cfg {String} invalidClass @hide
23345 * @cfg {String} invalidText @hide
23348 * @cfg {String} msgFx @hide
23351 * @cfg {String} validateOnBlur @hide
23360 Roo.namespace('Roo.bootstrap.htmleditor');
23362 * @class Roo.bootstrap.HtmlEditorToolbar1
23367 new Roo.bootstrap.HtmlEditor({
23370 new Roo.bootstrap.HtmlEditorToolbar1({
23371 disable : { fonts: 1 , format: 1, ..., ... , ...],
23377 * @cfg {Object} disable List of elements to disable..
23378 * @cfg {Array} btns List of additional buttons.
23382 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23385 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23388 Roo.apply(this, config);
23390 // default disabled, based on 'good practice'..
23391 this.disable = this.disable || {};
23392 Roo.applyIf(this.disable, {
23395 specialElements : true
23397 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23399 this.editor = config.editor;
23400 this.editorcore = config.editor.editorcore;
23402 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23404 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23405 // dont call parent... till later.
23407 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23412 editorcore : false,
23417 "h1","h2","h3","h4","h5","h6",
23419 "abbr", "acronym", "address", "cite", "samp", "var",
23423 onRender : function(ct, position)
23425 // Roo.log("Call onRender: " + this.xtype);
23427 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23429 this.el.dom.style.marginBottom = '0';
23431 var editorcore = this.editorcore;
23432 var editor= this.editor;
23435 var btn = function(id,cmd , toggle, handler, html){
23437 var event = toggle ? 'toggle' : 'click';
23442 xns: Roo.bootstrap,
23445 enableToggle:toggle !== false,
23447 pressed : toggle ? false : null,
23450 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23451 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23457 // var cb_box = function...
23462 xns: Roo.bootstrap,
23463 glyphicon : 'font',
23467 xns: Roo.bootstrap,
23471 Roo.each(this.formats, function(f) {
23472 style.menu.items.push({
23474 xns: Roo.bootstrap,
23475 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23480 editorcore.insertTag(this.tagname);
23487 children.push(style);
23489 btn('bold',false,true);
23490 btn('italic',false,true);
23491 btn('align-left', 'justifyleft',true);
23492 btn('align-center', 'justifycenter',true);
23493 btn('align-right' , 'justifyright',true);
23494 btn('link', false, false, function(btn) {
23495 //Roo.log("create link?");
23496 var url = prompt(this.createLinkText, this.defaultLinkValue);
23497 if(url && url != 'http:/'+'/'){
23498 this.editorcore.relayCmd('createlink', url);
23501 btn('list','insertunorderedlist',true);
23502 btn('pencil', false,true, function(btn){
23504 this.toggleSourceEdit(btn.pressed);
23507 if (this.editor.btns.length > 0) {
23508 for (var i = 0; i<this.editor.btns.length; i++) {
23509 children.push(this.editor.btns[i]);
23517 xns: Roo.bootstrap,
23522 xns: Roo.bootstrap,
23527 cog.menu.items.push({
23529 xns: Roo.bootstrap,
23530 html : Clean styles,
23535 editorcore.insertTag(this.tagname);
23544 this.xtype = 'NavSimplebar';
23546 for(var i=0;i< children.length;i++) {
23548 this.buttons.add(this.addxtypeChild(children[i]));
23552 editor.on('editorevent', this.updateToolbar, this);
23554 onBtnClick : function(id)
23556 this.editorcore.relayCmd(id);
23557 this.editorcore.focus();
23561 * Protected method that will not generally be called directly. It triggers
23562 * a toolbar update by reading the markup state of the current selection in the editor.
23564 updateToolbar: function(){
23566 if(!this.editorcore.activated){
23567 this.editor.onFirstFocus(); // is this neeed?
23571 var btns = this.buttons;
23572 var doc = this.editorcore.doc;
23573 btns.get('bold').setActive(doc.queryCommandState('bold'));
23574 btns.get('italic').setActive(doc.queryCommandState('italic'));
23575 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23577 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23578 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23579 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23581 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23582 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23585 var ans = this.editorcore.getAllAncestors();
23586 if (this.formatCombo) {
23589 var store = this.formatCombo.store;
23590 this.formatCombo.setValue("");
23591 for (var i =0; i < ans.length;i++) {
23592 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23594 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23602 // hides menus... - so this cant be on a menu...
23603 Roo.bootstrap.MenuMgr.hideAll();
23605 Roo.bootstrap.MenuMgr.hideAll();
23606 //this.editorsyncValue();
23608 onFirstFocus: function() {
23609 this.buttons.each(function(item){
23613 toggleSourceEdit : function(sourceEditMode){
23616 if(sourceEditMode){
23617 Roo.log("disabling buttons");
23618 this.buttons.each( function(item){
23619 if(item.cmd != 'pencil'){
23625 Roo.log("enabling buttons");
23626 if(this.editorcore.initialized){
23627 this.buttons.each( function(item){
23633 Roo.log("calling toggole on editor");
23634 // tell the editor that it's been pressed..
23635 this.editor.toggleSourceEdit(sourceEditMode);
23645 * @class Roo.bootstrap.Table.AbstractSelectionModel
23646 * @extends Roo.util.Observable
23647 * Abstract base class for grid SelectionModels. It provides the interface that should be
23648 * implemented by descendant classes. This class should not be directly instantiated.
23651 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23652 this.locked = false;
23653 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23657 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23658 /** @ignore Called by the grid automatically. Do not call directly. */
23659 init : function(grid){
23665 * Locks the selections.
23668 this.locked = true;
23672 * Unlocks the selections.
23674 unlock : function(){
23675 this.locked = false;
23679 * Returns true if the selections are locked.
23680 * @return {Boolean}
23682 isLocked : function(){
23683 return this.locked;
23687 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23688 * @class Roo.bootstrap.Table.RowSelectionModel
23689 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23690 * It supports multiple selections and keyboard selection/navigation.
23692 * @param {Object} config
23695 Roo.bootstrap.Table.RowSelectionModel = function(config){
23696 Roo.apply(this, config);
23697 this.selections = new Roo.util.MixedCollection(false, function(o){
23702 this.lastActive = false;
23706 * @event selectionchange
23707 * Fires when the selection changes
23708 * @param {SelectionModel} this
23710 "selectionchange" : true,
23712 * @event afterselectionchange
23713 * Fires after the selection changes (eg. by key press or clicking)
23714 * @param {SelectionModel} this
23716 "afterselectionchange" : true,
23718 * @event beforerowselect
23719 * Fires when a row is selected being selected, return false to cancel.
23720 * @param {SelectionModel} this
23721 * @param {Number} rowIndex The selected index
23722 * @param {Boolean} keepExisting False if other selections will be cleared
23724 "beforerowselect" : true,
23727 * Fires when a row is selected.
23728 * @param {SelectionModel} this
23729 * @param {Number} rowIndex The selected index
23730 * @param {Roo.data.Record} r The record
23732 "rowselect" : true,
23734 * @event rowdeselect
23735 * Fires when a row is deselected.
23736 * @param {SelectionModel} this
23737 * @param {Number} rowIndex The selected index
23739 "rowdeselect" : true
23741 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23742 this.locked = false;
23745 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23747 * @cfg {Boolean} singleSelect
23748 * True to allow selection of only one row at a time (defaults to false)
23750 singleSelect : false,
23753 initEvents : function()
23756 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23757 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23758 //}else{ // allow click to work like normal
23759 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23761 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23762 this.grid.on("rowclick", this.handleMouseDown, this);
23764 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23765 "up" : function(e){
23767 this.selectPrevious(e.shiftKey);
23768 }else if(this.last !== false && this.lastActive !== false){
23769 var last = this.last;
23770 this.selectRange(this.last, this.lastActive-1);
23771 this.grid.getView().focusRow(this.lastActive);
23772 if(last !== false){
23776 this.selectFirstRow();
23778 this.fireEvent("afterselectionchange", this);
23780 "down" : function(e){
23782 this.selectNext(e.shiftKey);
23783 }else if(this.last !== false && this.lastActive !== false){
23784 var last = this.last;
23785 this.selectRange(this.last, this.lastActive+1);
23786 this.grid.getView().focusRow(this.lastActive);
23787 if(last !== false){
23791 this.selectFirstRow();
23793 this.fireEvent("afterselectionchange", this);
23797 this.grid.store.on('load', function(){
23798 this.selections.clear();
23801 var view = this.grid.view;
23802 view.on("refresh", this.onRefresh, this);
23803 view.on("rowupdated", this.onRowUpdated, this);
23804 view.on("rowremoved", this.onRemove, this);
23809 onRefresh : function()
23811 var ds = this.grid.store, i, v = this.grid.view;
23812 var s = this.selections;
23813 s.each(function(r){
23814 if((i = ds.indexOfId(r.id)) != -1){
23823 onRemove : function(v, index, r){
23824 this.selections.remove(r);
23828 onRowUpdated : function(v, index, r){
23829 if(this.isSelected(r)){
23830 v.onRowSelect(index);
23836 * @param {Array} records The records to select
23837 * @param {Boolean} keepExisting (optional) True to keep existing selections
23839 selectRecords : function(records, keepExisting)
23842 this.clearSelections();
23844 var ds = this.grid.store;
23845 for(var i = 0, len = records.length; i < len; i++){
23846 this.selectRow(ds.indexOf(records[i]), true);
23851 * Gets the number of selected rows.
23854 getCount : function(){
23855 return this.selections.length;
23859 * Selects the first row in the grid.
23861 selectFirstRow : function(){
23866 * Select the last row.
23867 * @param {Boolean} keepExisting (optional) True to keep existing selections
23869 selectLastRow : function(keepExisting){
23870 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23871 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23875 * Selects the row immediately following the last selected row.
23876 * @param {Boolean} keepExisting (optional) True to keep existing selections
23878 selectNext : function(keepExisting)
23880 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23881 this.selectRow(this.last+1, keepExisting);
23882 this.grid.getView().focusRow(this.last);
23887 * Selects the row that precedes the last selected row.
23888 * @param {Boolean} keepExisting (optional) True to keep existing selections
23890 selectPrevious : function(keepExisting){
23892 this.selectRow(this.last-1, keepExisting);
23893 this.grid.getView().focusRow(this.last);
23898 * Returns the selected records
23899 * @return {Array} Array of selected records
23901 getSelections : function(){
23902 return [].concat(this.selections.items);
23906 * Returns the first selected record.
23909 getSelected : function(){
23910 return this.selections.itemAt(0);
23915 * Clears all selections.
23917 clearSelections : function(fast)
23923 var ds = this.grid.store;
23924 var s = this.selections;
23925 s.each(function(r){
23926 this.deselectRow(ds.indexOfId(r.id));
23930 this.selections.clear();
23937 * Selects all rows.
23939 selectAll : function(){
23943 this.selections.clear();
23944 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23945 this.selectRow(i, true);
23950 * Returns True if there is a selection.
23951 * @return {Boolean}
23953 hasSelection : function(){
23954 return this.selections.length > 0;
23958 * Returns True if the specified row is selected.
23959 * @param {Number/Record} record The record or index of the record to check
23960 * @return {Boolean}
23962 isSelected : function(index){
23963 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23964 return (r && this.selections.key(r.id) ? true : false);
23968 * Returns True if the specified record id is selected.
23969 * @param {String} id The id of record to check
23970 * @return {Boolean}
23972 isIdSelected : function(id){
23973 return (this.selections.key(id) ? true : false);
23978 handleMouseDBClick : function(e, t){
23982 handleMouseDown : function(e, t)
23984 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23985 if(this.isLocked() || rowIndex < 0 ){
23988 if(e.shiftKey && this.last !== false){
23989 var last = this.last;
23990 this.selectRange(last, rowIndex, e.ctrlKey);
23991 this.last = last; // reset the last
23995 var isSelected = this.isSelected(rowIndex);
23996 //Roo.log("select row:" + rowIndex);
23998 this.deselectRow(rowIndex);
24000 this.selectRow(rowIndex, true);
24004 if(e.button !== 0 && isSelected){
24005 alert('rowIndex 2: ' + rowIndex);
24006 view.focusRow(rowIndex);
24007 }else if(e.ctrlKey && isSelected){
24008 this.deselectRow(rowIndex);
24009 }else if(!isSelected){
24010 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24011 view.focusRow(rowIndex);
24015 this.fireEvent("afterselectionchange", this);
24018 handleDragableRowClick : function(grid, rowIndex, e)
24020 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24021 this.selectRow(rowIndex, false);
24022 grid.view.focusRow(rowIndex);
24023 this.fireEvent("afterselectionchange", this);
24028 * Selects multiple rows.
24029 * @param {Array} rows Array of the indexes of the row to select
24030 * @param {Boolean} keepExisting (optional) True to keep existing selections
24032 selectRows : function(rows, keepExisting){
24034 this.clearSelections();
24036 for(var i = 0, len = rows.length; i < len; i++){
24037 this.selectRow(rows[i], true);
24042 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24043 * @param {Number} startRow The index of the first row in the range
24044 * @param {Number} endRow The index of the last row in the range
24045 * @param {Boolean} keepExisting (optional) True to retain existing selections
24047 selectRange : function(startRow, endRow, keepExisting){
24052 this.clearSelections();
24054 if(startRow <= endRow){
24055 for(var i = startRow; i <= endRow; i++){
24056 this.selectRow(i, true);
24059 for(var i = startRow; i >= endRow; i--){
24060 this.selectRow(i, true);
24066 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24067 * @param {Number} startRow The index of the first row in the range
24068 * @param {Number} endRow The index of the last row in the range
24070 deselectRange : function(startRow, endRow, preventViewNotify){
24074 for(var i = startRow; i <= endRow; i++){
24075 this.deselectRow(i, preventViewNotify);
24081 * @param {Number} row The index of the row to select
24082 * @param {Boolean} keepExisting (optional) True to keep existing selections
24084 selectRow : function(index, keepExisting, preventViewNotify)
24086 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24089 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24090 if(!keepExisting || this.singleSelect){
24091 this.clearSelections();
24094 var r = this.grid.store.getAt(index);
24095 //console.log('selectRow - record id :' + r.id);
24097 this.selections.add(r);
24098 this.last = this.lastActive = index;
24099 if(!preventViewNotify){
24100 var proxy = new Roo.Element(
24101 this.grid.getRowDom(index)
24103 proxy.addClass('bg-info info');
24105 this.fireEvent("rowselect", this, index, r);
24106 this.fireEvent("selectionchange", this);
24112 * @param {Number} row The index of the row to deselect
24114 deselectRow : function(index, preventViewNotify)
24119 if(this.last == index){
24122 if(this.lastActive == index){
24123 this.lastActive = false;
24126 var r = this.grid.store.getAt(index);
24131 this.selections.remove(r);
24132 //.console.log('deselectRow - record id :' + r.id);
24133 if(!preventViewNotify){
24135 var proxy = new Roo.Element(
24136 this.grid.getRowDom(index)
24138 proxy.removeClass('bg-info info');
24140 this.fireEvent("rowdeselect", this, index);
24141 this.fireEvent("selectionchange", this);
24145 restoreLast : function(){
24147 this.last = this._last;
24152 acceptsNav : function(row, col, cm){
24153 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24157 onEditorKey : function(field, e){
24158 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24163 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24165 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24167 }else if(k == e.ENTER && !e.ctrlKey){
24171 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24173 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24175 }else if(k == e.ESC){
24179 g.startEditing(newCell[0], newCell[1]);
24185 * Ext JS Library 1.1.1
24186 * Copyright(c) 2006-2007, Ext JS, LLC.
24188 * Originally Released Under LGPL - original licence link has changed is not relivant.
24191 * <script type="text/javascript">
24195 * @class Roo.bootstrap.PagingToolbar
24196 * @extends Roo.bootstrap.NavSimplebar
24197 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24199 * Create a new PagingToolbar
24200 * @param {Object} config The config object
24201 * @param {Roo.data.Store} store
24203 Roo.bootstrap.PagingToolbar = function(config)
24205 // old args format still supported... - xtype is prefered..
24206 // created from xtype...
24208 this.ds = config.dataSource;
24210 if (config.store && !this.ds) {
24211 this.store= Roo.factory(config.store, Roo.data);
24212 this.ds = this.store;
24213 this.ds.xmodule = this.xmodule || false;
24216 this.toolbarItems = [];
24217 if (config.items) {
24218 this.toolbarItems = config.items;
24221 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24226 this.bind(this.ds);
24229 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24233 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24235 * @cfg {Roo.data.Store} dataSource
24236 * The underlying data store providing the paged data
24239 * @cfg {String/HTMLElement/Element} container
24240 * container The id or element that will contain the toolbar
24243 * @cfg {Boolean} displayInfo
24244 * True to display the displayMsg (defaults to false)
24247 * @cfg {Number} pageSize
24248 * The number of records to display per page (defaults to 20)
24252 * @cfg {String} displayMsg
24253 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24255 displayMsg : 'Displaying {0} - {1} of {2}',
24257 * @cfg {String} emptyMsg
24258 * The message to display when no records are found (defaults to "No data to display")
24260 emptyMsg : 'No data to display',
24262 * Customizable piece of the default paging text (defaults to "Page")
24265 beforePageText : "Page",
24267 * Customizable piece of the default paging text (defaults to "of %0")
24270 afterPageText : "of {0}",
24272 * Customizable piece of the default paging text (defaults to "First Page")
24275 firstText : "First Page",
24277 * Customizable piece of the default paging text (defaults to "Previous Page")
24280 prevText : "Previous Page",
24282 * Customizable piece of the default paging text (defaults to "Next Page")
24285 nextText : "Next Page",
24287 * Customizable piece of the default paging text (defaults to "Last Page")
24290 lastText : "Last Page",
24292 * Customizable piece of the default paging text (defaults to "Refresh")
24295 refreshText : "Refresh",
24299 onRender : function(ct, position)
24301 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24302 this.navgroup.parentId = this.id;
24303 this.navgroup.onRender(this.el, null);
24304 // add the buttons to the navgroup
24306 if(this.displayInfo){
24307 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24308 this.displayEl = this.el.select('.x-paging-info', true).first();
24309 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24310 // this.displayEl = navel.el.select('span',true).first();
24316 Roo.each(_this.buttons, function(e){ // this might need to use render????
24317 Roo.factory(e).onRender(_this.el, null);
24321 Roo.each(_this.toolbarItems, function(e) {
24322 _this.navgroup.addItem(e);
24326 this.first = this.navgroup.addItem({
24327 tooltip: this.firstText,
24329 icon : 'fa fa-backward',
24331 preventDefault: true,
24332 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24335 this.prev = this.navgroup.addItem({
24336 tooltip: this.prevText,
24338 icon : 'fa fa-step-backward',
24340 preventDefault: true,
24341 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24343 //this.addSeparator();
24346 var field = this.navgroup.addItem( {
24348 cls : 'x-paging-position',
24350 html : this.beforePageText +
24351 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24352 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24355 this.field = field.el.select('input', true).first();
24356 this.field.on("keydown", this.onPagingKeydown, this);
24357 this.field.on("focus", function(){this.dom.select();});
24360 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24361 //this.field.setHeight(18);
24362 //this.addSeparator();
24363 this.next = this.navgroup.addItem({
24364 tooltip: this.nextText,
24366 html : ' <i class="fa fa-step-forward">',
24368 preventDefault: true,
24369 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24371 this.last = this.navgroup.addItem({
24372 tooltip: this.lastText,
24373 icon : 'fa fa-forward',
24376 preventDefault: true,
24377 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24379 //this.addSeparator();
24380 this.loading = this.navgroup.addItem({
24381 tooltip: this.refreshText,
24382 icon: 'fa fa-refresh',
24383 preventDefault: true,
24384 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24390 updateInfo : function(){
24391 if(this.displayEl){
24392 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24393 var msg = count == 0 ?
24397 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24399 this.displayEl.update(msg);
24404 onLoad : function(ds, r, o)
24406 this.cursor = o.params ? o.params.start : 0;
24407 var d = this.getPageData(),
24412 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24413 this.field.dom.value = ap;
24414 this.first.setDisabled(ap == 1);
24415 this.prev.setDisabled(ap == 1);
24416 this.next.setDisabled(ap == ps);
24417 this.last.setDisabled(ap == ps);
24418 this.loading.enable();
24423 getPageData : function(){
24424 var total = this.ds.getTotalCount();
24427 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24428 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24433 onLoadError : function(){
24434 this.loading.enable();
24438 onPagingKeydown : function(e){
24439 var k = e.getKey();
24440 var d = this.getPageData();
24442 var v = this.field.dom.value, pageNum;
24443 if(!v || isNaN(pageNum = parseInt(v, 10))){
24444 this.field.dom.value = d.activePage;
24447 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24448 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24451 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))
24453 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24454 this.field.dom.value = pageNum;
24455 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24458 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24460 var v = this.field.dom.value, pageNum;
24461 var increment = (e.shiftKey) ? 10 : 1;
24462 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24465 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24466 this.field.dom.value = d.activePage;
24469 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24471 this.field.dom.value = parseInt(v, 10) + increment;
24472 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24473 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24480 beforeLoad : function(){
24482 this.loading.disable();
24487 onClick : function(which){
24496 ds.load({params:{start: 0, limit: this.pageSize}});
24499 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24502 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24505 var total = ds.getTotalCount();
24506 var extra = total % this.pageSize;
24507 var lastStart = extra ? (total - extra) : total-this.pageSize;
24508 ds.load({params:{start: lastStart, limit: this.pageSize}});
24511 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24517 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24518 * @param {Roo.data.Store} store The data store to unbind
24520 unbind : function(ds){
24521 ds.un("beforeload", this.beforeLoad, this);
24522 ds.un("load", this.onLoad, this);
24523 ds.un("loadexception", this.onLoadError, this);
24524 ds.un("remove", this.updateInfo, this);
24525 ds.un("add", this.updateInfo, this);
24526 this.ds = undefined;
24530 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24531 * @param {Roo.data.Store} store The data store to bind
24533 bind : function(ds){
24534 ds.on("beforeload", this.beforeLoad, this);
24535 ds.on("load", this.onLoad, this);
24536 ds.on("loadexception", this.onLoadError, this);
24537 ds.on("remove", this.updateInfo, this);
24538 ds.on("add", this.updateInfo, this);
24549 * @class Roo.bootstrap.MessageBar
24550 * @extends Roo.bootstrap.Component
24551 * Bootstrap MessageBar class
24552 * @cfg {String} html contents of the MessageBar
24553 * @cfg {String} weight (info | success | warning | danger) default info
24554 * @cfg {String} beforeClass insert the bar before the given class
24555 * @cfg {Boolean} closable (true | false) default false
24556 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24559 * Create a new Element
24560 * @param {Object} config The config object
24563 Roo.bootstrap.MessageBar = function(config){
24564 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24567 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24573 beforeClass: 'bootstrap-sticky-wrap',
24575 getAutoCreate : function(){
24579 cls: 'alert alert-dismissable alert-' + this.weight,
24584 html: this.html || ''
24590 cfg.cls += ' alert-messages-fixed';
24604 onRender : function(ct, position)
24606 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24609 var cfg = Roo.apply({}, this.getAutoCreate());
24613 cfg.cls += ' ' + this.cls;
24616 cfg.style = this.style;
24618 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24620 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24623 this.el.select('>button.close').on('click', this.hide, this);
24629 if (!this.rendered) {
24635 this.fireEvent('show', this);
24641 if (!this.rendered) {
24647 this.fireEvent('hide', this);
24650 update : function()
24652 // var e = this.el.dom.firstChild;
24654 // if(this.closable){
24655 // e = e.nextSibling;
24658 // e.data = this.html || '';
24660 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24676 * @class Roo.bootstrap.Graph
24677 * @extends Roo.bootstrap.Component
24678 * Bootstrap Graph class
24682 @cfg {String} graphtype bar | vbar | pie
24683 @cfg {number} g_x coodinator | centre x (pie)
24684 @cfg {number} g_y coodinator | centre y (pie)
24685 @cfg {number} g_r radius (pie)
24686 @cfg {number} g_height height of the chart (respected by all elements in the set)
24687 @cfg {number} g_width width of the chart (respected by all elements in the set)
24688 @cfg {Object} title The title of the chart
24691 -opts (object) options for the chart
24693 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24694 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24696 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.
24697 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24699 o stretch (boolean)
24701 -opts (object) options for the pie
24704 o startAngle (number)
24705 o endAngle (number)
24709 * Create a new Input
24710 * @param {Object} config The config object
24713 Roo.bootstrap.Graph = function(config){
24714 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24720 * The img click event for the img.
24721 * @param {Roo.EventObject} e
24727 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24738 //g_colors: this.colors,
24745 getAutoCreate : function(){
24756 onRender : function(ct,position){
24759 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24761 if (typeof(Raphael) == 'undefined') {
24762 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24766 this.raphael = Raphael(this.el.dom);
24768 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24769 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24770 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24771 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24773 r.text(160, 10, "Single Series Chart").attr(txtattr);
24774 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24775 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24776 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24778 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24779 r.barchart(330, 10, 300, 220, data1);
24780 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24781 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24784 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24785 // r.barchart(30, 30, 560, 250, xdata, {
24786 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24787 // axis : "0 0 1 1",
24788 // axisxlabels : xdata
24789 // //yvalues : cols,
24792 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24794 // this.load(null,xdata,{
24795 // axis : "0 0 1 1",
24796 // axisxlabels : xdata
24801 load : function(graphtype,xdata,opts)
24803 this.raphael.clear();
24805 graphtype = this.graphtype;
24810 var r = this.raphael,
24811 fin = function () {
24812 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24814 fout = function () {
24815 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24817 pfin = function() {
24818 this.sector.stop();
24819 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24822 this.label[0].stop();
24823 this.label[0].attr({ r: 7.5 });
24824 this.label[1].attr({ "font-weight": 800 });
24827 pfout = function() {
24828 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24831 this.label[0].animate({ r: 5 }, 500, "bounce");
24832 this.label[1].attr({ "font-weight": 400 });
24838 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24841 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24844 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24845 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24847 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24854 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24859 setTitle: function(o)
24864 initEvents: function() {
24867 this.el.on('click', this.onClick, this);
24871 onClick : function(e)
24873 Roo.log('img onclick');
24874 this.fireEvent('click', this, e);
24886 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24889 * @class Roo.bootstrap.dash.NumberBox
24890 * @extends Roo.bootstrap.Component
24891 * Bootstrap NumberBox class
24892 * @cfg {String} headline Box headline
24893 * @cfg {String} content Box content
24894 * @cfg {String} icon Box icon
24895 * @cfg {String} footer Footer text
24896 * @cfg {String} fhref Footer href
24899 * Create a new NumberBox
24900 * @param {Object} config The config object
24904 Roo.bootstrap.dash.NumberBox = function(config){
24905 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24909 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24918 getAutoCreate : function(){
24922 cls : 'small-box ',
24930 cls : 'roo-headline',
24931 html : this.headline
24935 cls : 'roo-content',
24936 html : this.content
24950 cls : 'ion ' + this.icon
24959 cls : 'small-box-footer',
24960 href : this.fhref || '#',
24964 cfg.cn.push(footer);
24971 onRender : function(ct,position){
24972 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24979 setHeadline: function (value)
24981 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24984 setFooter: function (value, href)
24986 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24989 this.el.select('a.small-box-footer',true).first().attr('href', href);
24994 setContent: function (value)
24996 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24999 initEvents: function()
25013 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25016 * @class Roo.bootstrap.dash.TabBox
25017 * @extends Roo.bootstrap.Component
25018 * Bootstrap TabBox class
25019 * @cfg {String} title Title of the TabBox
25020 * @cfg {String} icon Icon of the TabBox
25021 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25022 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25025 * Create a new TabBox
25026 * @param {Object} config The config object
25030 Roo.bootstrap.dash.TabBox = function(config){
25031 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25036 * When a pane is added
25037 * @param {Roo.bootstrap.dash.TabPane} pane
25041 * @event activatepane
25042 * When a pane is activated
25043 * @param {Roo.bootstrap.dash.TabPane} pane
25045 "activatepane" : true
25053 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25058 tabScrollable : false,
25060 getChildContainer : function()
25062 return this.el.select('.tab-content', true).first();
25065 getAutoCreate : function(){
25069 cls: 'pull-left header',
25077 cls: 'fa ' + this.icon
25083 cls: 'nav nav-tabs pull-right',
25089 if(this.tabScrollable){
25096 cls: 'nav nav-tabs pull-right',
25107 cls: 'nav-tabs-custom',
25112 cls: 'tab-content no-padding',
25120 initEvents : function()
25122 //Roo.log('add add pane handler');
25123 this.on('addpane', this.onAddPane, this);
25126 * Updates the box title
25127 * @param {String} html to set the title to.
25129 setTitle : function(value)
25131 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25133 onAddPane : function(pane)
25135 this.panes.push(pane);
25136 //Roo.log('addpane');
25138 // tabs are rendere left to right..
25139 if(!this.showtabs){
25143 var ctr = this.el.select('.nav-tabs', true).first();
25146 var existing = ctr.select('.nav-tab',true);
25147 var qty = existing.getCount();;
25150 var tab = ctr.createChild({
25152 cls : 'nav-tab' + (qty ? '' : ' active'),
25160 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25163 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25165 pane.el.addClass('active');
25170 onTabClick : function(ev,un,ob,pane)
25172 //Roo.log('tab - prev default');
25173 ev.preventDefault();
25176 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25177 pane.tab.addClass('active');
25178 //Roo.log(pane.title);
25179 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25180 // technically we should have a deactivate event.. but maybe add later.
25181 // and it should not de-activate the selected tab...
25182 this.fireEvent('activatepane', pane);
25183 pane.el.addClass('active');
25184 pane.fireEvent('activate');
25189 getActivePane : function()
25192 Roo.each(this.panes, function(p) {
25193 if(p.el.hasClass('active')){
25214 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25216 * @class Roo.bootstrap.TabPane
25217 * @extends Roo.bootstrap.Component
25218 * Bootstrap TabPane class
25219 * @cfg {Boolean} active (false | true) Default false
25220 * @cfg {String} title title of panel
25224 * Create a new TabPane
25225 * @param {Object} config The config object
25228 Roo.bootstrap.dash.TabPane = function(config){
25229 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25235 * When a pane is activated
25236 * @param {Roo.bootstrap.dash.TabPane} pane
25243 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25248 // the tabBox that this is attached to.
25251 getAutoCreate : function()
25259 cfg.cls += ' active';
25264 initEvents : function()
25266 //Roo.log('trigger add pane handler');
25267 this.parent().fireEvent('addpane', this)
25271 * Updates the tab title
25272 * @param {String} html to set the title to.
25274 setTitle: function(str)
25280 this.tab.select('a', true).first().dom.innerHTML = str;
25297 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25300 * @class Roo.bootstrap.menu.Menu
25301 * @extends Roo.bootstrap.Component
25302 * Bootstrap Menu class - container for Menu
25303 * @cfg {String} html Text of the menu
25304 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25305 * @cfg {String} icon Font awesome icon
25306 * @cfg {String} pos Menu align to (top | bottom) default bottom
25310 * Create a new Menu
25311 * @param {Object} config The config object
25315 Roo.bootstrap.menu.Menu = function(config){
25316 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25320 * @event beforeshow
25321 * Fires before this menu is displayed
25322 * @param {Roo.bootstrap.menu.Menu} this
25326 * @event beforehide
25327 * Fires before this menu is hidden
25328 * @param {Roo.bootstrap.menu.Menu} this
25333 * Fires after this menu is displayed
25334 * @param {Roo.bootstrap.menu.Menu} this
25339 * Fires after this menu is hidden
25340 * @param {Roo.bootstrap.menu.Menu} this
25345 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25346 * @param {Roo.bootstrap.menu.Menu} this
25347 * @param {Roo.EventObject} e
25354 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25358 weight : 'default',
25363 getChildContainer : function() {
25364 if(this.isSubMenu){
25368 return this.el.select('ul.dropdown-menu', true).first();
25371 getAutoCreate : function()
25376 cls : 'roo-menu-text',
25384 cls : 'fa ' + this.icon
25395 cls : 'dropdown-button btn btn-' + this.weight,
25400 cls : 'dropdown-toggle btn btn-' + this.weight,
25410 cls : 'dropdown-menu'
25416 if(this.pos == 'top'){
25417 cfg.cls += ' dropup';
25420 if(this.isSubMenu){
25423 cls : 'dropdown-menu'
25430 onRender : function(ct, position)
25432 this.isSubMenu = ct.hasClass('dropdown-submenu');
25434 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25437 initEvents : function()
25439 if(this.isSubMenu){
25443 this.hidden = true;
25445 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25446 this.triggerEl.on('click', this.onTriggerPress, this);
25448 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25449 this.buttonEl.on('click', this.onClick, this);
25455 if(this.isSubMenu){
25459 return this.el.select('ul.dropdown-menu', true).first();
25462 onClick : function(e)
25464 this.fireEvent("click", this, e);
25467 onTriggerPress : function(e)
25469 if (this.isVisible()) {
25476 isVisible : function(){
25477 return !this.hidden;
25482 this.fireEvent("beforeshow", this);
25484 this.hidden = false;
25485 this.el.addClass('open');
25487 Roo.get(document).on("mouseup", this.onMouseUp, this);
25489 this.fireEvent("show", this);
25496 this.fireEvent("beforehide", this);
25498 this.hidden = true;
25499 this.el.removeClass('open');
25501 Roo.get(document).un("mouseup", this.onMouseUp);
25503 this.fireEvent("hide", this);
25506 onMouseUp : function()
25520 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25523 * @class Roo.bootstrap.menu.Item
25524 * @extends Roo.bootstrap.Component
25525 * Bootstrap MenuItem class
25526 * @cfg {Boolean} submenu (true | false) default false
25527 * @cfg {String} html text of the item
25528 * @cfg {String} href the link
25529 * @cfg {Boolean} disable (true | false) default false
25530 * @cfg {Boolean} preventDefault (true | false) default true
25531 * @cfg {String} icon Font awesome icon
25532 * @cfg {String} pos Submenu align to (left | right) default right
25536 * Create a new Item
25537 * @param {Object} config The config object
25541 Roo.bootstrap.menu.Item = function(config){
25542 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25546 * Fires when the mouse is hovering over this menu
25547 * @param {Roo.bootstrap.menu.Item} this
25548 * @param {Roo.EventObject} e
25553 * Fires when the mouse exits this menu
25554 * @param {Roo.bootstrap.menu.Item} this
25555 * @param {Roo.EventObject} e
25561 * The raw click event for the entire grid.
25562 * @param {Roo.EventObject} e
25568 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25573 preventDefault: true,
25578 getAutoCreate : function()
25583 cls : 'roo-menu-item-text',
25591 cls : 'fa ' + this.icon
25600 href : this.href || '#',
25607 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25611 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25613 if(this.pos == 'left'){
25614 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25621 initEvents : function()
25623 this.el.on('mouseover', this.onMouseOver, this);
25624 this.el.on('mouseout', this.onMouseOut, this);
25626 this.el.select('a', true).first().on('click', this.onClick, this);
25630 onClick : function(e)
25632 if(this.preventDefault){
25633 e.preventDefault();
25636 this.fireEvent("click", this, e);
25639 onMouseOver : function(e)
25641 if(this.submenu && this.pos == 'left'){
25642 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25645 this.fireEvent("mouseover", this, e);
25648 onMouseOut : function(e)
25650 this.fireEvent("mouseout", this, e);
25662 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25665 * @class Roo.bootstrap.menu.Separator
25666 * @extends Roo.bootstrap.Component
25667 * Bootstrap Separator class
25670 * Create a new Separator
25671 * @param {Object} config The config object
25675 Roo.bootstrap.menu.Separator = function(config){
25676 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25679 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25681 getAutoCreate : function(){
25702 * @class Roo.bootstrap.Tooltip
25703 * Bootstrap Tooltip class
25704 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25705 * to determine which dom element triggers the tooltip.
25707 * It needs to add support for additional attributes like tooltip-position
25710 * Create a new Toolti
25711 * @param {Object} config The config object
25714 Roo.bootstrap.Tooltip = function(config){
25715 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25717 this.alignment = Roo.bootstrap.Tooltip.alignment;
25719 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25720 this.alignment = config.alignment;
25725 Roo.apply(Roo.bootstrap.Tooltip, {
25727 * @function init initialize tooltip monitoring.
25731 currentTip : false,
25732 currentRegion : false,
25738 Roo.get(document).on('mouseover', this.enter ,this);
25739 Roo.get(document).on('mouseout', this.leave, this);
25742 this.currentTip = new Roo.bootstrap.Tooltip();
25745 enter : function(ev)
25747 var dom = ev.getTarget();
25749 //Roo.log(['enter',dom]);
25750 var el = Roo.fly(dom);
25751 if (this.currentEl) {
25753 //Roo.log(this.currentEl);
25754 //Roo.log(this.currentEl.contains(dom));
25755 if (this.currentEl == el) {
25758 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25764 if (this.currentTip.el) {
25765 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25769 if(!el || el.dom == document){
25775 // you can not look for children, as if el is the body.. then everythign is the child..
25776 if (!el.attr('tooltip')) { //
25777 if (!el.select("[tooltip]").elements.length) {
25780 // is the mouse over this child...?
25781 bindEl = el.select("[tooltip]").first();
25782 var xy = ev.getXY();
25783 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25784 //Roo.log("not in region.");
25787 //Roo.log("child element over..");
25790 this.currentEl = bindEl;
25791 this.currentTip.bind(bindEl);
25792 this.currentRegion = Roo.lib.Region.getRegion(dom);
25793 this.currentTip.enter();
25796 leave : function(ev)
25798 var dom = ev.getTarget();
25799 //Roo.log(['leave',dom]);
25800 if (!this.currentEl) {
25805 if (dom != this.currentEl.dom) {
25808 var xy = ev.getXY();
25809 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25812 // only activate leave if mouse cursor is outside... bounding box..
25817 if (this.currentTip) {
25818 this.currentTip.leave();
25820 //Roo.log('clear currentEl');
25821 this.currentEl = false;
25826 'left' : ['r-l', [-2,0], 'right'],
25827 'right' : ['l-r', [2,0], 'left'],
25828 'bottom' : ['t-b', [0,2], 'top'],
25829 'top' : [ 'b-t', [0,-2], 'bottom']
25835 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25840 delay : null, // can be { show : 300 , hide: 500}
25844 hoverState : null, //???
25846 placement : 'bottom',
25850 getAutoCreate : function(){
25857 cls : 'tooltip-arrow'
25860 cls : 'tooltip-inner'
25867 bind : function(el)
25873 enter : function () {
25875 if (this.timeout != null) {
25876 clearTimeout(this.timeout);
25879 this.hoverState = 'in';
25880 //Roo.log("enter - show");
25881 if (!this.delay || !this.delay.show) {
25886 this.timeout = setTimeout(function () {
25887 if (_t.hoverState == 'in') {
25890 }, this.delay.show);
25894 clearTimeout(this.timeout);
25896 this.hoverState = 'out';
25897 if (!this.delay || !this.delay.hide) {
25903 this.timeout = setTimeout(function () {
25904 //Roo.log("leave - timeout");
25906 if (_t.hoverState == 'out') {
25908 Roo.bootstrap.Tooltip.currentEl = false;
25913 show : function (msg)
25916 this.render(document.body);
25919 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25921 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25923 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25925 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25927 var placement = typeof this.placement == 'function' ?
25928 this.placement.call(this, this.el, on_el) :
25931 var autoToken = /\s?auto?\s?/i;
25932 var autoPlace = autoToken.test(placement);
25934 placement = placement.replace(autoToken, '') || 'top';
25938 //this.el.setXY([0,0]);
25940 //this.el.dom.style.display='block';
25942 //this.el.appendTo(on_el);
25944 var p = this.getPosition();
25945 var box = this.el.getBox();
25951 var align = this.alignment[placement];
25953 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25955 if(placement == 'top' || placement == 'bottom'){
25957 placement = 'right';
25960 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25961 placement = 'left';
25964 var scroll = Roo.select('body', true).first().getScroll();
25966 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25972 this.el.alignTo(this.bindEl, align[0],align[1]);
25973 //var arrow = this.el.select('.arrow',true).first();
25974 //arrow.set(align[2],
25976 this.el.addClass(placement);
25978 this.el.addClass('in fade');
25980 this.hoverState = null;
25982 if (this.el.hasClass('fade')) {
25993 //this.el.setXY([0,0]);
25994 this.el.removeClass('in');
26010 * @class Roo.bootstrap.LocationPicker
26011 * @extends Roo.bootstrap.Component
26012 * Bootstrap LocationPicker class
26013 * @cfg {Number} latitude Position when init default 0
26014 * @cfg {Number} longitude Position when init default 0
26015 * @cfg {Number} zoom default 15
26016 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26017 * @cfg {Boolean} mapTypeControl default false
26018 * @cfg {Boolean} disableDoubleClickZoom default false
26019 * @cfg {Boolean} scrollwheel default true
26020 * @cfg {Boolean} streetViewControl default false
26021 * @cfg {Number} radius default 0
26022 * @cfg {String} locationName
26023 * @cfg {Boolean} draggable default true
26024 * @cfg {Boolean} enableAutocomplete default false
26025 * @cfg {Boolean} enableReverseGeocode default true
26026 * @cfg {String} markerTitle
26029 * Create a new LocationPicker
26030 * @param {Object} config The config object
26034 Roo.bootstrap.LocationPicker = function(config){
26036 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26041 * Fires when the picker initialized.
26042 * @param {Roo.bootstrap.LocationPicker} this
26043 * @param {Google Location} location
26047 * @event positionchanged
26048 * Fires when the picker position changed.
26049 * @param {Roo.bootstrap.LocationPicker} this
26050 * @param {Google Location} location
26052 positionchanged : true,
26055 * Fires when the map resize.
26056 * @param {Roo.bootstrap.LocationPicker} this
26061 * Fires when the map show.
26062 * @param {Roo.bootstrap.LocationPicker} this
26067 * Fires when the map hide.
26068 * @param {Roo.bootstrap.LocationPicker} this
26073 * Fires when click the map.
26074 * @param {Roo.bootstrap.LocationPicker} this
26075 * @param {Map event} e
26079 * @event mapRightClick
26080 * Fires when right click the map.
26081 * @param {Roo.bootstrap.LocationPicker} this
26082 * @param {Map event} e
26084 mapRightClick : true,
26086 * @event markerClick
26087 * Fires when click the marker.
26088 * @param {Roo.bootstrap.LocationPicker} this
26089 * @param {Map event} e
26091 markerClick : true,
26093 * @event markerRightClick
26094 * Fires when right click the marker.
26095 * @param {Roo.bootstrap.LocationPicker} this
26096 * @param {Map event} e
26098 markerRightClick : true,
26100 * @event OverlayViewDraw
26101 * Fires when OverlayView Draw
26102 * @param {Roo.bootstrap.LocationPicker} this
26104 OverlayViewDraw : true,
26106 * @event OverlayViewOnAdd
26107 * Fires when OverlayView Draw
26108 * @param {Roo.bootstrap.LocationPicker} this
26110 OverlayViewOnAdd : true,
26112 * @event OverlayViewOnRemove
26113 * Fires when OverlayView Draw
26114 * @param {Roo.bootstrap.LocationPicker} this
26116 OverlayViewOnRemove : true,
26118 * @event OverlayViewShow
26119 * Fires when OverlayView Draw
26120 * @param {Roo.bootstrap.LocationPicker} this
26121 * @param {Pixel} cpx
26123 OverlayViewShow : true,
26125 * @event OverlayViewHide
26126 * Fires when OverlayView Draw
26127 * @param {Roo.bootstrap.LocationPicker} this
26129 OverlayViewHide : true,
26131 * @event loadexception
26132 * Fires when load google lib failed.
26133 * @param {Roo.bootstrap.LocationPicker} this
26135 loadexception : true
26140 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26142 gMapContext: false,
26148 mapTypeControl: false,
26149 disableDoubleClickZoom: false,
26151 streetViewControl: false,
26155 enableAutocomplete: false,
26156 enableReverseGeocode: true,
26159 getAutoCreate: function()
26164 cls: 'roo-location-picker'
26170 initEvents: function(ct, position)
26172 if(!this.el.getWidth() || this.isApplied()){
26176 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26181 initial: function()
26183 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26184 this.fireEvent('loadexception', this);
26188 if(!this.mapTypeId){
26189 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26192 this.gMapContext = this.GMapContext();
26194 this.initOverlayView();
26196 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26200 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26201 _this.setPosition(_this.gMapContext.marker.position);
26204 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26205 _this.fireEvent('mapClick', this, event);
26209 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26210 _this.fireEvent('mapRightClick', this, event);
26214 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26215 _this.fireEvent('markerClick', this, event);
26219 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26220 _this.fireEvent('markerRightClick', this, event);
26224 this.setPosition(this.gMapContext.location);
26226 this.fireEvent('initial', this, this.gMapContext.location);
26229 initOverlayView: function()
26233 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26237 _this.fireEvent('OverlayViewDraw', _this);
26242 _this.fireEvent('OverlayViewOnAdd', _this);
26245 onRemove: function()
26247 _this.fireEvent('OverlayViewOnRemove', _this);
26250 show: function(cpx)
26252 _this.fireEvent('OverlayViewShow', _this, cpx);
26257 _this.fireEvent('OverlayViewHide', _this);
26263 fromLatLngToContainerPixel: function(event)
26265 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26268 isApplied: function()
26270 return this.getGmapContext() == false ? false : true;
26273 getGmapContext: function()
26275 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26278 GMapContext: function()
26280 var position = new google.maps.LatLng(this.latitude, this.longitude);
26282 var _map = new google.maps.Map(this.el.dom, {
26285 mapTypeId: this.mapTypeId,
26286 mapTypeControl: this.mapTypeControl,
26287 disableDoubleClickZoom: this.disableDoubleClickZoom,
26288 scrollwheel: this.scrollwheel,
26289 streetViewControl: this.streetViewControl,
26290 locationName: this.locationName,
26291 draggable: this.draggable,
26292 enableAutocomplete: this.enableAutocomplete,
26293 enableReverseGeocode: this.enableReverseGeocode
26296 var _marker = new google.maps.Marker({
26297 position: position,
26299 title: this.markerTitle,
26300 draggable: this.draggable
26307 location: position,
26308 radius: this.radius,
26309 locationName: this.locationName,
26310 addressComponents: {
26311 formatted_address: null,
26312 addressLine1: null,
26313 addressLine2: null,
26315 streetNumber: null,
26319 stateOrProvince: null
26322 domContainer: this.el.dom,
26323 geodecoder: new google.maps.Geocoder()
26327 drawCircle: function(center, radius, options)
26329 if (this.gMapContext.circle != null) {
26330 this.gMapContext.circle.setMap(null);
26334 options = Roo.apply({}, options, {
26335 strokeColor: "#0000FF",
26336 strokeOpacity: .35,
26338 fillColor: "#0000FF",
26342 options.map = this.gMapContext.map;
26343 options.radius = radius;
26344 options.center = center;
26345 this.gMapContext.circle = new google.maps.Circle(options);
26346 return this.gMapContext.circle;
26352 setPosition: function(location)
26354 this.gMapContext.location = location;
26355 this.gMapContext.marker.setPosition(location);
26356 this.gMapContext.map.panTo(location);
26357 this.drawCircle(location, this.gMapContext.radius, {});
26361 if (this.gMapContext.settings.enableReverseGeocode) {
26362 this.gMapContext.geodecoder.geocode({
26363 latLng: this.gMapContext.location
26364 }, function(results, status) {
26366 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26367 _this.gMapContext.locationName = results[0].formatted_address;
26368 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26370 _this.fireEvent('positionchanged', this, location);
26377 this.fireEvent('positionchanged', this, location);
26382 google.maps.event.trigger(this.gMapContext.map, "resize");
26384 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26386 this.fireEvent('resize', this);
26389 setPositionByLatLng: function(latitude, longitude)
26391 this.setPosition(new google.maps.LatLng(latitude, longitude));
26394 getCurrentPosition: function()
26397 latitude: this.gMapContext.location.lat(),
26398 longitude: this.gMapContext.location.lng()
26402 getAddressName: function()
26404 return this.gMapContext.locationName;
26407 getAddressComponents: function()
26409 return this.gMapContext.addressComponents;
26412 address_component_from_google_geocode: function(address_components)
26416 for (var i = 0; i < address_components.length; i++) {
26417 var component = address_components[i];
26418 if (component.types.indexOf("postal_code") >= 0) {
26419 result.postalCode = component.short_name;
26420 } else if (component.types.indexOf("street_number") >= 0) {
26421 result.streetNumber = component.short_name;
26422 } else if (component.types.indexOf("route") >= 0) {
26423 result.streetName = component.short_name;
26424 } else if (component.types.indexOf("neighborhood") >= 0) {
26425 result.city = component.short_name;
26426 } else if (component.types.indexOf("locality") >= 0) {
26427 result.city = component.short_name;
26428 } else if (component.types.indexOf("sublocality") >= 0) {
26429 result.district = component.short_name;
26430 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26431 result.stateOrProvince = component.short_name;
26432 } else if (component.types.indexOf("country") >= 0) {
26433 result.country = component.short_name;
26437 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26438 result.addressLine2 = "";
26442 setZoomLevel: function(zoom)
26444 this.gMapContext.map.setZoom(zoom);
26457 this.fireEvent('show', this);
26468 this.fireEvent('hide', this);
26473 Roo.apply(Roo.bootstrap.LocationPicker, {
26475 OverlayView : function(map, options)
26477 options = options || {};
26491 * @class Roo.bootstrap.Alert
26492 * @extends Roo.bootstrap.Component
26493 * Bootstrap Alert class
26494 * @cfg {String} title The title of alert
26495 * @cfg {String} html The content of alert
26496 * @cfg {String} weight ( success | info | warning | danger )
26497 * @cfg {String} faicon font-awesomeicon
26500 * Create a new alert
26501 * @param {Object} config The config object
26505 Roo.bootstrap.Alert = function(config){
26506 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26510 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26517 getAutoCreate : function()
26526 cls : 'roo-alert-icon'
26531 cls : 'roo-alert-title',
26536 cls : 'roo-alert-text',
26543 cfg.cn[0].cls += ' fa ' + this.faicon;
26547 cfg.cls += ' alert-' + this.weight;
26553 initEvents: function()
26555 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26558 setTitle : function(str)
26560 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26563 setText : function(str)
26565 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26568 setWeight : function(weight)
26571 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26574 this.weight = weight;
26576 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26579 setIcon : function(icon)
26582 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26585 this.faicon = icon;
26587 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26608 * @class Roo.bootstrap.UploadCropbox
26609 * @extends Roo.bootstrap.Component
26610 * Bootstrap UploadCropbox class
26611 * @cfg {String} emptyText show when image has been loaded
26612 * @cfg {String} rotateNotify show when image too small to rotate
26613 * @cfg {Number} errorTimeout default 3000
26614 * @cfg {Number} minWidth default 300
26615 * @cfg {Number} minHeight default 300
26616 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26617 * @cfg {Boolean} isDocument (true|false) default false
26618 * @cfg {String} url action url
26619 * @cfg {String} paramName default 'imageUpload'
26620 * @cfg {String} method default POST
26621 * @cfg {Boolean} loadMask (true|false) default true
26622 * @cfg {Boolean} loadingText default 'Loading...'
26625 * Create a new UploadCropbox
26626 * @param {Object} config The config object
26629 Roo.bootstrap.UploadCropbox = function(config){
26630 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26634 * @event beforeselectfile
26635 * Fire before select file
26636 * @param {Roo.bootstrap.UploadCropbox} this
26638 "beforeselectfile" : true,
26641 * Fire after initEvent
26642 * @param {Roo.bootstrap.UploadCropbox} this
26647 * Fire after initEvent
26648 * @param {Roo.bootstrap.UploadCropbox} this
26649 * @param {String} data
26654 * Fire when preparing the file data
26655 * @param {Roo.bootstrap.UploadCropbox} this
26656 * @param {Object} file
26661 * Fire when get exception
26662 * @param {Roo.bootstrap.UploadCropbox} this
26663 * @param {XMLHttpRequest} xhr
26665 "exception" : true,
26667 * @event beforeloadcanvas
26668 * Fire before load the canvas
26669 * @param {Roo.bootstrap.UploadCropbox} this
26670 * @param {String} src
26672 "beforeloadcanvas" : true,
26675 * Fire when trash image
26676 * @param {Roo.bootstrap.UploadCropbox} this
26681 * Fire when download the image
26682 * @param {Roo.bootstrap.UploadCropbox} this
26686 * @event footerbuttonclick
26687 * Fire when footerbuttonclick
26688 * @param {Roo.bootstrap.UploadCropbox} this
26689 * @param {String} type
26691 "footerbuttonclick" : true,
26695 * @param {Roo.bootstrap.UploadCropbox} this
26700 * Fire when rotate the image
26701 * @param {Roo.bootstrap.UploadCropbox} this
26702 * @param {String} pos
26707 * Fire when inspect the file
26708 * @param {Roo.bootstrap.UploadCropbox} this
26709 * @param {Object} file
26714 * Fire when xhr upload the file
26715 * @param {Roo.bootstrap.UploadCropbox} this
26716 * @param {Object} data
26721 * Fire when arrange the file data
26722 * @param {Roo.bootstrap.UploadCropbox} this
26723 * @param {Object} formData
26728 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26731 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26733 emptyText : 'Click to upload image',
26734 rotateNotify : 'Image is too small to rotate',
26735 errorTimeout : 3000,
26749 cropType : 'image/jpeg',
26751 canvasLoaded : false,
26752 isDocument : false,
26754 paramName : 'imageUpload',
26756 loadingText : 'Loading...',
26759 getAutoCreate : function()
26763 cls : 'roo-upload-cropbox',
26767 cls : 'roo-upload-cropbox-selector',
26772 cls : 'roo-upload-cropbox-body',
26773 style : 'cursor:pointer',
26777 cls : 'roo-upload-cropbox-preview'
26781 cls : 'roo-upload-cropbox-thumb'
26785 cls : 'roo-upload-cropbox-empty-notify',
26786 html : this.emptyText
26790 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26791 html : this.rotateNotify
26797 cls : 'roo-upload-cropbox-footer',
26800 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26810 onRender : function(ct, position)
26812 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26814 if (this.buttons.length) {
26816 Roo.each(this.buttons, function(bb) {
26818 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26820 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26826 this.maskEl = this.el;
26830 initEvents : function()
26832 this.urlAPI = (window.createObjectURL && window) ||
26833 (window.URL && URL.revokeObjectURL && URL) ||
26834 (window.webkitURL && webkitURL);
26836 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26837 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26839 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26840 this.selectorEl.hide();
26842 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26843 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26845 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26846 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26847 this.thumbEl.hide();
26849 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26850 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26852 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26853 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26854 this.errorEl.hide();
26856 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26857 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26858 this.footerEl.hide();
26860 this.setThumbBoxSize();
26866 this.fireEvent('initial', this);
26873 window.addEventListener("resize", function() { _this.resize(); } );
26875 this.bodyEl.on('click', this.beforeSelectFile, this);
26878 this.bodyEl.on('touchstart', this.onTouchStart, this);
26879 this.bodyEl.on('touchmove', this.onTouchMove, this);
26880 this.bodyEl.on('touchend', this.onTouchEnd, this);
26884 this.bodyEl.on('mousedown', this.onMouseDown, this);
26885 this.bodyEl.on('mousemove', this.onMouseMove, this);
26886 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26887 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26888 Roo.get(document).on('mouseup', this.onMouseUp, this);
26891 this.selectorEl.on('change', this.onFileSelected, this);
26897 this.baseScale = 1;
26899 this.baseRotate = 1;
26900 this.dragable = false;
26901 this.pinching = false;
26904 this.cropData = false;
26905 this.notifyEl.dom.innerHTML = this.emptyText;
26907 this.selectorEl.dom.value = '';
26911 resize : function()
26913 if(this.fireEvent('resize', this) != false){
26914 this.setThumbBoxPosition();
26915 this.setCanvasPosition();
26919 onFooterButtonClick : function(e, el, o, type)
26922 case 'rotate-left' :
26923 this.onRotateLeft(e);
26925 case 'rotate-right' :
26926 this.onRotateRight(e);
26929 this.beforeSelectFile(e);
26944 this.fireEvent('footerbuttonclick', this, type);
26947 beforeSelectFile : function(e)
26949 e.preventDefault();
26951 if(this.fireEvent('beforeselectfile', this) != false){
26952 this.selectorEl.dom.click();
26956 onFileSelected : function(e)
26958 e.preventDefault();
26960 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26964 var file = this.selectorEl.dom.files[0];
26966 if(this.fireEvent('inspect', this, file) != false){
26967 this.prepare(file);
26972 trash : function(e)
26974 this.fireEvent('trash', this);
26977 download : function(e)
26979 this.fireEvent('download', this);
26982 loadCanvas : function(src)
26984 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26988 this.imageEl = document.createElement('img');
26992 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26994 this.imageEl.src = src;
26998 onLoadCanvas : function()
27000 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27001 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27003 this.bodyEl.un('click', this.beforeSelectFile, this);
27005 this.notifyEl.hide();
27006 this.thumbEl.show();
27007 this.footerEl.show();
27009 this.baseRotateLevel();
27011 if(this.isDocument){
27012 this.setThumbBoxSize();
27015 this.setThumbBoxPosition();
27017 this.baseScaleLevel();
27023 this.canvasLoaded = true;
27026 this.maskEl.unmask();
27031 setCanvasPosition : function()
27033 if(!this.canvasEl){
27037 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27038 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27040 this.previewEl.setLeft(pw);
27041 this.previewEl.setTop(ph);
27045 onMouseDown : function(e)
27049 this.dragable = true;
27050 this.pinching = false;
27052 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27053 this.dragable = false;
27057 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27058 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27062 onMouseMove : function(e)
27066 if(!this.canvasLoaded){
27070 if (!this.dragable){
27074 var minX = Math.ceil(this.thumbEl.getLeft(true));
27075 var minY = Math.ceil(this.thumbEl.getTop(true));
27077 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27078 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27080 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27081 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27083 x = x - this.mouseX;
27084 y = y - this.mouseY;
27086 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27087 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27089 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27090 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27092 this.previewEl.setLeft(bgX);
27093 this.previewEl.setTop(bgY);
27095 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27096 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27099 onMouseUp : function(e)
27103 this.dragable = false;
27106 onMouseWheel : function(e)
27110 this.startScale = this.scale;
27112 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27114 if(!this.zoomable()){
27115 this.scale = this.startScale;
27124 zoomable : function()
27126 var minScale = this.thumbEl.getWidth() / this.minWidth;
27128 if(this.minWidth < this.minHeight){
27129 minScale = this.thumbEl.getHeight() / this.minHeight;
27132 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27133 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27137 (this.rotate == 0 || this.rotate == 180) &&
27139 width > this.imageEl.OriginWidth ||
27140 height > this.imageEl.OriginHeight ||
27141 (width < this.minWidth && height < this.minHeight)
27149 (this.rotate == 90 || this.rotate == 270) &&
27151 width > this.imageEl.OriginWidth ||
27152 height > this.imageEl.OriginHeight ||
27153 (width < this.minHeight && height < this.minWidth)
27160 !this.isDocument &&
27161 (this.rotate == 0 || this.rotate == 180) &&
27163 width < this.minWidth ||
27164 width > this.imageEl.OriginWidth ||
27165 height < this.minHeight ||
27166 height > this.imageEl.OriginHeight
27173 !this.isDocument &&
27174 (this.rotate == 90 || this.rotate == 270) &&
27176 width < this.minHeight ||
27177 width > this.imageEl.OriginWidth ||
27178 height < this.minWidth ||
27179 height > this.imageEl.OriginHeight
27189 onRotateLeft : function(e)
27191 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27193 var minScale = this.thumbEl.getWidth() / this.minWidth;
27195 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27196 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27198 this.startScale = this.scale;
27200 while (this.getScaleLevel() < minScale){
27202 this.scale = this.scale + 1;
27204 if(!this.zoomable()){
27209 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27210 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27215 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27222 this.scale = this.startScale;
27224 this.onRotateFail();
27229 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27231 if(this.isDocument){
27232 this.setThumbBoxSize();
27233 this.setThumbBoxPosition();
27234 this.setCanvasPosition();
27239 this.fireEvent('rotate', this, 'left');
27243 onRotateRight : function(e)
27245 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27247 var minScale = this.thumbEl.getWidth() / this.minWidth;
27249 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27250 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27252 this.startScale = this.scale;
27254 while (this.getScaleLevel() < minScale){
27256 this.scale = this.scale + 1;
27258 if(!this.zoomable()){
27263 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27264 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27269 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27276 this.scale = this.startScale;
27278 this.onRotateFail();
27283 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27285 if(this.isDocument){
27286 this.setThumbBoxSize();
27287 this.setThumbBoxPosition();
27288 this.setCanvasPosition();
27293 this.fireEvent('rotate', this, 'right');
27296 onRotateFail : function()
27298 this.errorEl.show(true);
27302 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27307 this.previewEl.dom.innerHTML = '';
27309 var canvasEl = document.createElement("canvas");
27311 var contextEl = canvasEl.getContext("2d");
27313 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27314 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27315 var center = this.imageEl.OriginWidth / 2;
27317 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27318 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27319 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27320 center = this.imageEl.OriginHeight / 2;
27323 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27325 contextEl.translate(center, center);
27326 contextEl.rotate(this.rotate * Math.PI / 180);
27328 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27330 this.canvasEl = document.createElement("canvas");
27332 this.contextEl = this.canvasEl.getContext("2d");
27334 switch (this.rotate) {
27337 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27338 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27340 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27345 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27346 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27348 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27349 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);
27353 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27358 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27359 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27361 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27362 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);
27366 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);
27371 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27372 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27374 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27375 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27379 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);
27386 this.previewEl.appendChild(this.canvasEl);
27388 this.setCanvasPosition();
27393 if(!this.canvasLoaded){
27397 var imageCanvas = document.createElement("canvas");
27399 var imageContext = imageCanvas.getContext("2d");
27401 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27402 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27404 var center = imageCanvas.width / 2;
27406 imageContext.translate(center, center);
27408 imageContext.rotate(this.rotate * Math.PI / 180);
27410 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27412 var canvas = document.createElement("canvas");
27414 var context = canvas.getContext("2d");
27416 canvas.width = this.minWidth;
27417 canvas.height = this.minHeight;
27419 switch (this.rotate) {
27422 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27423 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27425 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27426 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27428 var targetWidth = this.minWidth - 2 * x;
27429 var targetHeight = this.minHeight - 2 * y;
27433 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27434 scale = targetWidth / width;
27437 if(x > 0 && y == 0){
27438 scale = targetHeight / height;
27441 if(x > 0 && y > 0){
27442 scale = targetWidth / width;
27444 if(width < height){
27445 scale = targetHeight / height;
27449 context.scale(scale, scale);
27451 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27452 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27454 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27455 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27457 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27462 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27463 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27465 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27466 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27468 var targetWidth = this.minWidth - 2 * x;
27469 var targetHeight = this.minHeight - 2 * y;
27473 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27474 scale = targetWidth / width;
27477 if(x > 0 && y == 0){
27478 scale = targetHeight / height;
27481 if(x > 0 && y > 0){
27482 scale = targetWidth / width;
27484 if(width < height){
27485 scale = targetHeight / height;
27489 context.scale(scale, scale);
27491 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27492 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27494 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27495 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27497 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27499 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27504 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27505 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27507 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27508 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27510 var targetWidth = this.minWidth - 2 * x;
27511 var targetHeight = this.minHeight - 2 * y;
27515 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27516 scale = targetWidth / width;
27519 if(x > 0 && y == 0){
27520 scale = targetHeight / height;
27523 if(x > 0 && y > 0){
27524 scale = targetWidth / width;
27526 if(width < height){
27527 scale = targetHeight / height;
27531 context.scale(scale, scale);
27533 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27534 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27536 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27537 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27539 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27540 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27542 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27547 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27548 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27550 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27551 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27553 var targetWidth = this.minWidth - 2 * x;
27554 var targetHeight = this.minHeight - 2 * y;
27558 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27559 scale = targetWidth / width;
27562 if(x > 0 && y == 0){
27563 scale = targetHeight / height;
27566 if(x > 0 && y > 0){
27567 scale = targetWidth / width;
27569 if(width < height){
27570 scale = targetHeight / height;
27574 context.scale(scale, scale);
27576 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27577 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27579 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27580 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27582 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27584 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27591 this.cropData = canvas.toDataURL(this.cropType);
27593 if(this.fireEvent('crop', this, this.cropData) !== false){
27594 this.process(this.file, this.cropData);
27601 setThumbBoxSize : function()
27605 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27606 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27607 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27609 this.minWidth = width;
27610 this.minHeight = height;
27612 if(this.rotate == 90 || this.rotate == 270){
27613 this.minWidth = height;
27614 this.minHeight = width;
27619 width = Math.ceil(this.minWidth * height / this.minHeight);
27621 if(this.minWidth > this.minHeight){
27623 height = Math.ceil(this.minHeight * width / this.minWidth);
27626 this.thumbEl.setStyle({
27627 width : width + 'px',
27628 height : height + 'px'
27635 setThumbBoxPosition : function()
27637 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27638 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27640 this.thumbEl.setLeft(x);
27641 this.thumbEl.setTop(y);
27645 baseRotateLevel : function()
27647 this.baseRotate = 1;
27650 typeof(this.exif) != 'undefined' &&
27651 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27652 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27654 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27657 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27661 baseScaleLevel : function()
27665 if(this.isDocument){
27667 if(this.baseRotate == 6 || this.baseRotate == 8){
27669 height = this.thumbEl.getHeight();
27670 this.baseScale = height / this.imageEl.OriginWidth;
27672 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27673 width = this.thumbEl.getWidth();
27674 this.baseScale = width / this.imageEl.OriginHeight;
27680 height = this.thumbEl.getHeight();
27681 this.baseScale = height / this.imageEl.OriginHeight;
27683 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27684 width = this.thumbEl.getWidth();
27685 this.baseScale = width / this.imageEl.OriginWidth;
27691 if(this.baseRotate == 6 || this.baseRotate == 8){
27693 width = this.thumbEl.getHeight();
27694 this.baseScale = width / this.imageEl.OriginHeight;
27696 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27697 height = this.thumbEl.getWidth();
27698 this.baseScale = height / this.imageEl.OriginHeight;
27701 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27702 height = this.thumbEl.getWidth();
27703 this.baseScale = height / this.imageEl.OriginHeight;
27705 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27706 width = this.thumbEl.getHeight();
27707 this.baseScale = width / this.imageEl.OriginWidth;
27714 width = this.thumbEl.getWidth();
27715 this.baseScale = width / this.imageEl.OriginWidth;
27717 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27718 height = this.thumbEl.getHeight();
27719 this.baseScale = height / this.imageEl.OriginHeight;
27722 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27724 height = this.thumbEl.getHeight();
27725 this.baseScale = height / this.imageEl.OriginHeight;
27727 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27728 width = this.thumbEl.getWidth();
27729 this.baseScale = width / this.imageEl.OriginWidth;
27737 getScaleLevel : function()
27739 return this.baseScale * Math.pow(1.1, this.scale);
27742 onTouchStart : function(e)
27744 if(!this.canvasLoaded){
27745 this.beforeSelectFile(e);
27749 var touches = e.browserEvent.touches;
27755 if(touches.length == 1){
27756 this.onMouseDown(e);
27760 if(touches.length != 2){
27766 for(var i = 0, finger; finger = touches[i]; i++){
27767 coords.push(finger.pageX, finger.pageY);
27770 var x = Math.pow(coords[0] - coords[2], 2);
27771 var y = Math.pow(coords[1] - coords[3], 2);
27773 this.startDistance = Math.sqrt(x + y);
27775 this.startScale = this.scale;
27777 this.pinching = true;
27778 this.dragable = false;
27782 onTouchMove : function(e)
27784 if(!this.pinching && !this.dragable){
27788 var touches = e.browserEvent.touches;
27795 this.onMouseMove(e);
27801 for(var i = 0, finger; finger = touches[i]; i++){
27802 coords.push(finger.pageX, finger.pageY);
27805 var x = Math.pow(coords[0] - coords[2], 2);
27806 var y = Math.pow(coords[1] - coords[3], 2);
27808 this.endDistance = Math.sqrt(x + y);
27810 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27812 if(!this.zoomable()){
27813 this.scale = this.startScale;
27821 onTouchEnd : function(e)
27823 this.pinching = false;
27824 this.dragable = false;
27828 process : function(file, crop)
27831 this.maskEl.mask(this.loadingText);
27834 this.xhr = new XMLHttpRequest();
27836 file.xhr = this.xhr;
27838 this.xhr.open(this.method, this.url, true);
27841 "Accept": "application/json",
27842 "Cache-Control": "no-cache",
27843 "X-Requested-With": "XMLHttpRequest"
27846 for (var headerName in headers) {
27847 var headerValue = headers[headerName];
27849 this.xhr.setRequestHeader(headerName, headerValue);
27855 this.xhr.onload = function()
27857 _this.xhrOnLoad(_this.xhr);
27860 this.xhr.onerror = function()
27862 _this.xhrOnError(_this.xhr);
27865 var formData = new FormData();
27867 formData.append('returnHTML', 'NO');
27870 formData.append('crop', crop);
27873 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27874 formData.append(this.paramName, file, file.name);
27877 if(typeof(file.filename) != 'undefined'){
27878 formData.append('filename', file.filename);
27881 if(typeof(file.mimetype) != 'undefined'){
27882 formData.append('mimetype', file.mimetype);
27885 if(this.fireEvent('arrange', this, formData) != false){
27886 this.xhr.send(formData);
27890 xhrOnLoad : function(xhr)
27893 this.maskEl.unmask();
27896 if (xhr.readyState !== 4) {
27897 this.fireEvent('exception', this, xhr);
27901 var response = Roo.decode(xhr.responseText);
27903 if(!response.success){
27904 this.fireEvent('exception', this, xhr);
27908 var response = Roo.decode(xhr.responseText);
27910 this.fireEvent('upload', this, response);
27914 xhrOnError : function()
27917 this.maskEl.unmask();
27920 Roo.log('xhr on error');
27922 var response = Roo.decode(xhr.responseText);
27928 prepare : function(file)
27931 this.maskEl.mask(this.loadingText);
27937 if(typeof(file) === 'string'){
27938 this.loadCanvas(file);
27942 if(!file || !this.urlAPI){
27947 this.cropType = file.type;
27951 if(this.fireEvent('prepare', this, this.file) != false){
27953 var reader = new FileReader();
27955 reader.onload = function (e) {
27956 if (e.target.error) {
27957 Roo.log(e.target.error);
27961 var buffer = e.target.result,
27962 dataView = new DataView(buffer),
27964 maxOffset = dataView.byteLength - 4,
27968 if (dataView.getUint16(0) === 0xffd8) {
27969 while (offset < maxOffset) {
27970 markerBytes = dataView.getUint16(offset);
27972 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27973 markerLength = dataView.getUint16(offset + 2) + 2;
27974 if (offset + markerLength > dataView.byteLength) {
27975 Roo.log('Invalid meta data: Invalid segment size.');
27979 if(markerBytes == 0xffe1){
27980 _this.parseExifData(
27987 offset += markerLength;
27997 var url = _this.urlAPI.createObjectURL(_this.file);
27999 _this.loadCanvas(url);
28004 reader.readAsArrayBuffer(this.file);
28010 parseExifData : function(dataView, offset, length)
28012 var tiffOffset = offset + 10,
28016 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28017 // No Exif data, might be XMP data instead
28021 // Check for the ASCII code for "Exif" (0x45786966):
28022 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28023 // No Exif data, might be XMP data instead
28026 if (tiffOffset + 8 > dataView.byteLength) {
28027 Roo.log('Invalid Exif data: Invalid segment size.');
28030 // Check for the two null bytes:
28031 if (dataView.getUint16(offset + 8) !== 0x0000) {
28032 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28035 // Check the byte alignment:
28036 switch (dataView.getUint16(tiffOffset)) {
28038 littleEndian = true;
28041 littleEndian = false;
28044 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28047 // Check for the TIFF tag marker (0x002A):
28048 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28049 Roo.log('Invalid Exif data: Missing TIFF marker.');
28052 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28053 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28055 this.parseExifTags(
28058 tiffOffset + dirOffset,
28063 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28068 if (dirOffset + 6 > dataView.byteLength) {
28069 Roo.log('Invalid Exif data: Invalid directory offset.');
28072 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28073 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28074 if (dirEndOffset + 4 > dataView.byteLength) {
28075 Roo.log('Invalid Exif data: Invalid directory size.');
28078 for (i = 0; i < tagsNumber; i += 1) {
28082 dirOffset + 2 + 12 * i, // tag offset
28086 // Return the offset to the next directory:
28087 return dataView.getUint32(dirEndOffset, littleEndian);
28090 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28092 var tag = dataView.getUint16(offset, littleEndian);
28094 this.exif[tag] = this.getExifValue(
28098 dataView.getUint16(offset + 2, littleEndian), // tag type
28099 dataView.getUint32(offset + 4, littleEndian), // tag length
28104 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28106 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28115 Roo.log('Invalid Exif data: Invalid tag type.');
28119 tagSize = tagType.size * length;
28120 // Determine if the value is contained in the dataOffset bytes,
28121 // or if the value at the dataOffset is a pointer to the actual data:
28122 dataOffset = tagSize > 4 ?
28123 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28124 if (dataOffset + tagSize > dataView.byteLength) {
28125 Roo.log('Invalid Exif data: Invalid data offset.');
28128 if (length === 1) {
28129 return tagType.getValue(dataView, dataOffset, littleEndian);
28132 for (i = 0; i < length; i += 1) {
28133 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28136 if (tagType.ascii) {
28138 // Concatenate the chars:
28139 for (i = 0; i < values.length; i += 1) {
28141 // Ignore the terminating NULL byte(s):
28142 if (c === '\u0000') {
28154 Roo.apply(Roo.bootstrap.UploadCropbox, {
28156 'Orientation': 0x0112
28160 1: 0, //'top-left',
28162 3: 180, //'bottom-right',
28163 // 4: 'bottom-left',
28165 6: 90, //'right-top',
28166 // 7: 'right-bottom',
28167 8: 270 //'left-bottom'
28171 // byte, 8-bit unsigned int:
28173 getValue: function (dataView, dataOffset) {
28174 return dataView.getUint8(dataOffset);
28178 // ascii, 8-bit byte:
28180 getValue: function (dataView, dataOffset) {
28181 return String.fromCharCode(dataView.getUint8(dataOffset));
28186 // short, 16 bit int:
28188 getValue: function (dataView, dataOffset, littleEndian) {
28189 return dataView.getUint16(dataOffset, littleEndian);
28193 // long, 32 bit int:
28195 getValue: function (dataView, dataOffset, littleEndian) {
28196 return dataView.getUint32(dataOffset, littleEndian);
28200 // rational = two long values, first is numerator, second is denominator:
28202 getValue: function (dataView, dataOffset, littleEndian) {
28203 return dataView.getUint32(dataOffset, littleEndian) /
28204 dataView.getUint32(dataOffset + 4, littleEndian);
28208 // slong, 32 bit signed int:
28210 getValue: function (dataView, dataOffset, littleEndian) {
28211 return dataView.getInt32(dataOffset, littleEndian);
28215 // srational, two slongs, first is numerator, second is denominator:
28217 getValue: function (dataView, dataOffset, littleEndian) {
28218 return dataView.getInt32(dataOffset, littleEndian) /
28219 dataView.getInt32(dataOffset + 4, littleEndian);
28229 cls : 'btn-group roo-upload-cropbox-rotate-left',
28230 action : 'rotate-left',
28234 cls : 'btn btn-default',
28235 html : '<i class="fa fa-undo"></i>'
28241 cls : 'btn-group roo-upload-cropbox-picture',
28242 action : 'picture',
28246 cls : 'btn btn-default',
28247 html : '<i class="fa fa-picture-o"></i>'
28253 cls : 'btn-group roo-upload-cropbox-rotate-right',
28254 action : 'rotate-right',
28258 cls : 'btn btn-default',
28259 html : '<i class="fa fa-repeat"></i>'
28267 cls : 'btn-group roo-upload-cropbox-rotate-left',
28268 action : 'rotate-left',
28272 cls : 'btn btn-default',
28273 html : '<i class="fa fa-undo"></i>'
28279 cls : 'btn-group roo-upload-cropbox-download',
28280 action : 'download',
28284 cls : 'btn btn-default',
28285 html : '<i class="fa fa-download"></i>'
28291 cls : 'btn-group roo-upload-cropbox-crop',
28296 cls : 'btn btn-default',
28297 html : '<i class="fa fa-crop"></i>'
28303 cls : 'btn-group roo-upload-cropbox-trash',
28308 cls : 'btn btn-default',
28309 html : '<i class="fa fa-trash"></i>'
28315 cls : 'btn-group roo-upload-cropbox-rotate-right',
28316 action : 'rotate-right',
28320 cls : 'btn btn-default',
28321 html : '<i class="fa fa-repeat"></i>'
28329 cls : 'btn-group roo-upload-cropbox-rotate-left',
28330 action : 'rotate-left',
28334 cls : 'btn btn-default',
28335 html : '<i class="fa fa-undo"></i>'
28341 cls : 'btn-group roo-upload-cropbox-rotate-right',
28342 action : 'rotate-right',
28346 cls : 'btn btn-default',
28347 html : '<i class="fa fa-repeat"></i>'
28360 * @class Roo.bootstrap.DocumentManager
28361 * @extends Roo.bootstrap.Component
28362 * Bootstrap DocumentManager class
28363 * @cfg {String} paramName default 'imageUpload'
28364 * @cfg {String} toolTipName default 'filename'
28365 * @cfg {String} method default POST
28366 * @cfg {String} url action url
28367 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28368 * @cfg {Boolean} multiple multiple upload default true
28369 * @cfg {Number} thumbSize default 300
28370 * @cfg {String} fieldLabel
28371 * @cfg {Number} labelWidth default 4
28372 * @cfg {String} labelAlign (left|top) default left
28373 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28374 * @cfg {Number} labellg set the width of label (1-12)
28375 * @cfg {Number} labelmd set the width of label (1-12)
28376 * @cfg {Number} labelsm set the width of label (1-12)
28377 * @cfg {Number} labelxs set the width of label (1-12)
28380 * Create a new DocumentManager
28381 * @param {Object} config The config object
28384 Roo.bootstrap.DocumentManager = function(config){
28385 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28388 this.delegates = [];
28393 * Fire when initial the DocumentManager
28394 * @param {Roo.bootstrap.DocumentManager} this
28399 * inspect selected file
28400 * @param {Roo.bootstrap.DocumentManager} this
28401 * @param {File} file
28406 * Fire when xhr load exception
28407 * @param {Roo.bootstrap.DocumentManager} this
28408 * @param {XMLHttpRequest} xhr
28410 "exception" : true,
28412 * @event afterupload
28413 * Fire when xhr load exception
28414 * @param {Roo.bootstrap.DocumentManager} this
28415 * @param {XMLHttpRequest} xhr
28417 "afterupload" : true,
28420 * prepare the form data
28421 * @param {Roo.bootstrap.DocumentManager} this
28422 * @param {Object} formData
28427 * Fire when remove the file
28428 * @param {Roo.bootstrap.DocumentManager} this
28429 * @param {Object} file
28434 * Fire after refresh the file
28435 * @param {Roo.bootstrap.DocumentManager} this
28440 * Fire after click the image
28441 * @param {Roo.bootstrap.DocumentManager} this
28442 * @param {Object} file
28447 * Fire when upload a image and editable set to true
28448 * @param {Roo.bootstrap.DocumentManager} this
28449 * @param {Object} file
28453 * @event beforeselectfile
28454 * Fire before select file
28455 * @param {Roo.bootstrap.DocumentManager} this
28457 "beforeselectfile" : true,
28460 * Fire before process file
28461 * @param {Roo.bootstrap.DocumentManager} this
28462 * @param {Object} file
28466 * @event previewrendered
28467 * Fire when preview rendered
28468 * @param {Roo.bootstrap.DocumentManager} this
28469 * @param {Object} file
28471 "previewrendered" : true
28476 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28485 paramName : 'imageUpload',
28486 toolTipName : 'filename',
28489 labelAlign : 'left',
28499 getAutoCreate : function()
28501 var managerWidget = {
28503 cls : 'roo-document-manager',
28507 cls : 'roo-document-manager-selector',
28512 cls : 'roo-document-manager-uploader',
28516 cls : 'roo-document-manager-upload-btn',
28517 html : '<i class="fa fa-plus"></i>'
28528 cls : 'column col-md-12',
28533 if(this.fieldLabel.length){
28538 cls : 'column col-md-12',
28539 html : this.fieldLabel
28543 cls : 'column col-md-12',
28548 if(this.labelAlign == 'left'){
28553 html : this.fieldLabel
28562 if(this.labelWidth > 12){
28563 content[0].style = "width: " + this.labelWidth + 'px';
28566 if(this.labelWidth < 13 && this.labelmd == 0){
28567 this.labelmd = this.labelWidth;
28570 if(this.labellg > 0){
28571 content[0].cls += ' col-lg-' + this.labellg;
28572 content[1].cls += ' col-lg-' + (12 - this.labellg);
28575 if(this.labelmd > 0){
28576 content[0].cls += ' col-md-' + this.labelmd;
28577 content[1].cls += ' col-md-' + (12 - this.labelmd);
28580 if(this.labelsm > 0){
28581 content[0].cls += ' col-sm-' + this.labelsm;
28582 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28585 if(this.labelxs > 0){
28586 content[0].cls += ' col-xs-' + this.labelxs;
28587 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28595 cls : 'row clearfix',
28603 initEvents : function()
28605 this.managerEl = this.el.select('.roo-document-manager', true).first();
28606 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28608 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28609 this.selectorEl.hide();
28612 this.selectorEl.attr('multiple', 'multiple');
28615 this.selectorEl.on('change', this.onFileSelected, this);
28617 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28618 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28620 this.uploader.on('click', this.onUploaderClick, this);
28622 this.renderProgressDialog();
28626 window.addEventListener("resize", function() { _this.refresh(); } );
28628 this.fireEvent('initial', this);
28631 renderProgressDialog : function()
28635 this.progressDialog = new Roo.bootstrap.Modal({
28636 cls : 'roo-document-manager-progress-dialog',
28637 allow_close : false,
28647 btnclick : function() {
28648 _this.uploadCancel();
28654 this.progressDialog.render(Roo.get(document.body));
28656 this.progress = new Roo.bootstrap.Progress({
28657 cls : 'roo-document-manager-progress',
28662 this.progress.render(this.progressDialog.getChildContainer());
28664 this.progressBar = new Roo.bootstrap.ProgressBar({
28665 cls : 'roo-document-manager-progress-bar',
28668 aria_valuemax : 12,
28672 this.progressBar.render(this.progress.getChildContainer());
28675 onUploaderClick : function(e)
28677 e.preventDefault();
28679 if(this.fireEvent('beforeselectfile', this) != false){
28680 this.selectorEl.dom.click();
28685 onFileSelected : function(e)
28687 e.preventDefault();
28689 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28693 Roo.each(this.selectorEl.dom.files, function(file){
28694 if(this.fireEvent('inspect', this, file) != false){
28695 this.files.push(file);
28705 this.selectorEl.dom.value = '';
28707 if(!this.files || !this.files.length){
28711 if(this.boxes > 0 && this.files.length > this.boxes){
28712 this.files = this.files.slice(0, this.boxes);
28715 this.uploader.show();
28717 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28718 this.uploader.hide();
28727 Roo.each(this.files, function(file){
28729 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28730 var f = this.renderPreview(file);
28735 if(file.type.indexOf('image') != -1){
28736 this.delegates.push(
28738 _this.process(file);
28739 }).createDelegate(this)
28747 _this.process(file);
28748 }).createDelegate(this)
28753 this.files = files;
28755 this.delegates = this.delegates.concat(docs);
28757 if(!this.delegates.length){
28762 this.progressBar.aria_valuemax = this.delegates.length;
28769 arrange : function()
28771 if(!this.delegates.length){
28772 this.progressDialog.hide();
28777 var delegate = this.delegates.shift();
28779 this.progressDialog.show();
28781 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28783 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28788 refresh : function()
28790 this.uploader.show();
28792 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28793 this.uploader.hide();
28796 Roo.isTouch ? this.closable(false) : this.closable(true);
28798 this.fireEvent('refresh', this);
28801 onRemove : function(e, el, o)
28803 e.preventDefault();
28805 this.fireEvent('remove', this, o);
28809 remove : function(o)
28813 Roo.each(this.files, function(file){
28814 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28823 this.files = files;
28830 Roo.each(this.files, function(file){
28835 file.target.remove();
28844 onClick : function(e, el, o)
28846 e.preventDefault();
28848 this.fireEvent('click', this, o);
28852 closable : function(closable)
28854 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28856 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28868 xhrOnLoad : function(xhr)
28870 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28874 if (xhr.readyState !== 4) {
28876 this.fireEvent('exception', this, xhr);
28880 var response = Roo.decode(xhr.responseText);
28882 if(!response.success){
28884 this.fireEvent('exception', this, xhr);
28888 var file = this.renderPreview(response.data);
28890 this.files.push(file);
28894 this.fireEvent('afterupload', this, xhr);
28898 xhrOnError : function(xhr)
28900 Roo.log('xhr on error');
28902 var response = Roo.decode(xhr.responseText);
28909 process : function(file)
28911 if(this.fireEvent('process', this, file) !== false){
28912 if(this.editable && file.type.indexOf('image') != -1){
28913 this.fireEvent('edit', this, file);
28917 this.uploadStart(file, false);
28924 uploadStart : function(file, crop)
28926 this.xhr = new XMLHttpRequest();
28928 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28933 file.xhr = this.xhr;
28935 this.managerEl.createChild({
28937 cls : 'roo-document-manager-loading',
28941 tooltip : file.name,
28942 cls : 'roo-document-manager-thumb',
28943 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28949 this.xhr.open(this.method, this.url, true);
28952 "Accept": "application/json",
28953 "Cache-Control": "no-cache",
28954 "X-Requested-With": "XMLHttpRequest"
28957 for (var headerName in headers) {
28958 var headerValue = headers[headerName];
28960 this.xhr.setRequestHeader(headerName, headerValue);
28966 this.xhr.onload = function()
28968 _this.xhrOnLoad(_this.xhr);
28971 this.xhr.onerror = function()
28973 _this.xhrOnError(_this.xhr);
28976 var formData = new FormData();
28978 formData.append('returnHTML', 'NO');
28981 formData.append('crop', crop);
28984 formData.append(this.paramName, file, file.name);
28991 if(this.fireEvent('prepare', this, formData, options) != false){
28993 if(options.manually){
28997 this.xhr.send(formData);
29001 this.uploadCancel();
29004 uploadCancel : function()
29010 this.delegates = [];
29012 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29019 renderPreview : function(file)
29021 if(typeof(file.target) != 'undefined' && file.target){
29025 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29027 var previewEl = this.managerEl.createChild({
29029 cls : 'roo-document-manager-preview',
29033 tooltip : file[this.toolTipName],
29034 cls : 'roo-document-manager-thumb',
29035 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29040 html : '<i class="fa fa-times-circle"></i>'
29045 var close = previewEl.select('button.close', true).first();
29047 close.on('click', this.onRemove, this, file);
29049 file.target = previewEl;
29051 var image = previewEl.select('img', true).first();
29055 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29057 image.on('click', this.onClick, this, file);
29059 this.fireEvent('previewrendered', this, file);
29065 onPreviewLoad : function(file, image)
29067 if(typeof(file.target) == 'undefined' || !file.target){
29071 var width = image.dom.naturalWidth || image.dom.width;
29072 var height = image.dom.naturalHeight || image.dom.height;
29074 if(width > height){
29075 file.target.addClass('wide');
29079 file.target.addClass('tall');
29084 uploadFromSource : function(file, crop)
29086 this.xhr = new XMLHttpRequest();
29088 this.managerEl.createChild({
29090 cls : 'roo-document-manager-loading',
29094 tooltip : file.name,
29095 cls : 'roo-document-manager-thumb',
29096 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29102 this.xhr.open(this.method, this.url, true);
29105 "Accept": "application/json",
29106 "Cache-Control": "no-cache",
29107 "X-Requested-With": "XMLHttpRequest"
29110 for (var headerName in headers) {
29111 var headerValue = headers[headerName];
29113 this.xhr.setRequestHeader(headerName, headerValue);
29119 this.xhr.onload = function()
29121 _this.xhrOnLoad(_this.xhr);
29124 this.xhr.onerror = function()
29126 _this.xhrOnError(_this.xhr);
29129 var formData = new FormData();
29131 formData.append('returnHTML', 'NO');
29133 formData.append('crop', crop);
29135 if(typeof(file.filename) != 'undefined'){
29136 formData.append('filename', file.filename);
29139 if(typeof(file.mimetype) != 'undefined'){
29140 formData.append('mimetype', file.mimetype);
29145 if(this.fireEvent('prepare', this, formData) != false){
29146 this.xhr.send(formData);
29156 * @class Roo.bootstrap.DocumentViewer
29157 * @extends Roo.bootstrap.Component
29158 * Bootstrap DocumentViewer class
29159 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29160 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29163 * Create a new DocumentViewer
29164 * @param {Object} config The config object
29167 Roo.bootstrap.DocumentViewer = function(config){
29168 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29173 * Fire after initEvent
29174 * @param {Roo.bootstrap.DocumentViewer} this
29180 * @param {Roo.bootstrap.DocumentViewer} this
29185 * Fire after download button
29186 * @param {Roo.bootstrap.DocumentViewer} this
29191 * Fire after trash button
29192 * @param {Roo.bootstrap.DocumentViewer} this
29199 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29201 showDownload : true,
29205 getAutoCreate : function()
29209 cls : 'roo-document-viewer',
29213 cls : 'roo-document-viewer-body',
29217 cls : 'roo-document-viewer-thumb',
29221 cls : 'roo-document-viewer-image'
29229 cls : 'roo-document-viewer-footer',
29232 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29236 cls : 'btn-group roo-document-viewer-download',
29240 cls : 'btn btn-default',
29241 html : '<i class="fa fa-download"></i>'
29247 cls : 'btn-group roo-document-viewer-trash',
29251 cls : 'btn btn-default',
29252 html : '<i class="fa fa-trash"></i>'
29265 initEvents : function()
29267 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29268 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29270 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29271 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29273 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29274 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29276 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29277 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29279 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29280 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29282 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29283 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29285 this.bodyEl.on('click', this.onClick, this);
29286 this.downloadBtn.on('click', this.onDownload, this);
29287 this.trashBtn.on('click', this.onTrash, this);
29289 this.downloadBtn.hide();
29290 this.trashBtn.hide();
29292 if(this.showDownload){
29293 this.downloadBtn.show();
29296 if(this.showTrash){
29297 this.trashBtn.show();
29300 if(!this.showDownload && !this.showTrash) {
29301 this.footerEl.hide();
29306 initial : function()
29308 this.fireEvent('initial', this);
29312 onClick : function(e)
29314 e.preventDefault();
29316 this.fireEvent('click', this);
29319 onDownload : function(e)
29321 e.preventDefault();
29323 this.fireEvent('download', this);
29326 onTrash : function(e)
29328 e.preventDefault();
29330 this.fireEvent('trash', this);
29342 * @class Roo.bootstrap.NavProgressBar
29343 * @extends Roo.bootstrap.Component
29344 * Bootstrap NavProgressBar class
29347 * Create a new nav progress bar
29348 * @param {Object} config The config object
29351 Roo.bootstrap.NavProgressBar = function(config){
29352 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29354 this.bullets = this.bullets || [];
29356 // Roo.bootstrap.NavProgressBar.register(this);
29360 * Fires when the active item changes
29361 * @param {Roo.bootstrap.NavProgressBar} this
29362 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29363 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29370 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29375 getAutoCreate : function()
29377 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29381 cls : 'roo-navigation-bar-group',
29385 cls : 'roo-navigation-top-bar'
29389 cls : 'roo-navigation-bullets-bar',
29393 cls : 'roo-navigation-bar'
29400 cls : 'roo-navigation-bottom-bar'
29410 initEvents: function()
29415 onRender : function(ct, position)
29417 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29419 if(this.bullets.length){
29420 Roo.each(this.bullets, function(b){
29429 addItem : function(cfg)
29431 var item = new Roo.bootstrap.NavProgressItem(cfg);
29433 item.parentId = this.id;
29434 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29437 var top = new Roo.bootstrap.Element({
29439 cls : 'roo-navigation-bar-text'
29442 var bottom = new Roo.bootstrap.Element({
29444 cls : 'roo-navigation-bar-text'
29447 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29448 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29450 var topText = new Roo.bootstrap.Element({
29452 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29455 var bottomText = new Roo.bootstrap.Element({
29457 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29460 topText.onRender(top.el, null);
29461 bottomText.onRender(bottom.el, null);
29464 item.bottomEl = bottom;
29467 this.barItems.push(item);
29472 getActive : function()
29474 var active = false;
29476 Roo.each(this.barItems, function(v){
29478 if (!v.isActive()) {
29490 setActiveItem : function(item)
29494 Roo.each(this.barItems, function(v){
29495 if (v.rid == item.rid) {
29499 if (v.isActive()) {
29500 v.setActive(false);
29505 item.setActive(true);
29507 this.fireEvent('changed', this, item, prev);
29510 getBarItem: function(rid)
29514 Roo.each(this.barItems, function(e) {
29515 if (e.rid != rid) {
29526 indexOfItem : function(item)
29530 Roo.each(this.barItems, function(v, i){
29532 if (v.rid != item.rid) {
29543 setActiveNext : function()
29545 var i = this.indexOfItem(this.getActive());
29547 if (i > this.barItems.length) {
29551 this.setActiveItem(this.barItems[i+1]);
29554 setActivePrev : function()
29556 var i = this.indexOfItem(this.getActive());
29562 this.setActiveItem(this.barItems[i-1]);
29565 format : function()
29567 if(!this.barItems.length){
29571 var width = 100 / this.barItems.length;
29573 Roo.each(this.barItems, function(i){
29574 i.el.setStyle('width', width + '%');
29575 i.topEl.el.setStyle('width', width + '%');
29576 i.bottomEl.el.setStyle('width', width + '%');
29585 * Nav Progress Item
29590 * @class Roo.bootstrap.NavProgressItem
29591 * @extends Roo.bootstrap.Component
29592 * Bootstrap NavProgressItem class
29593 * @cfg {String} rid the reference id
29594 * @cfg {Boolean} active (true|false) Is item active default false
29595 * @cfg {Boolean} disabled (true|false) Is item active default false
29596 * @cfg {String} html
29597 * @cfg {String} position (top|bottom) text position default bottom
29598 * @cfg {String} icon show icon instead of number
29601 * Create a new NavProgressItem
29602 * @param {Object} config The config object
29604 Roo.bootstrap.NavProgressItem = function(config){
29605 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29610 * The raw click event for the entire grid.
29611 * @param {Roo.bootstrap.NavProgressItem} this
29612 * @param {Roo.EventObject} e
29619 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29625 position : 'bottom',
29628 getAutoCreate : function()
29630 var iconCls = 'roo-navigation-bar-item-icon';
29632 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29636 cls: 'roo-navigation-bar-item',
29646 cfg.cls += ' active';
29649 cfg.cls += ' disabled';
29655 disable : function()
29657 this.setDisabled(true);
29660 enable : function()
29662 this.setDisabled(false);
29665 initEvents: function()
29667 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29669 this.iconEl.on('click', this.onClick, this);
29672 onClick : function(e)
29674 e.preventDefault();
29680 if(this.fireEvent('click', this, e) === false){
29684 this.parent().setActiveItem(this);
29687 isActive: function ()
29689 return this.active;
29692 setActive : function(state)
29694 if(this.active == state){
29698 this.active = state;
29701 this.el.addClass('active');
29705 this.el.removeClass('active');
29710 setDisabled : function(state)
29712 if(this.disabled == state){
29716 this.disabled = state;
29719 this.el.addClass('disabled');
29723 this.el.removeClass('disabled');
29726 tooltipEl : function()
29728 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29741 * @class Roo.bootstrap.FieldLabel
29742 * @extends Roo.bootstrap.Component
29743 * Bootstrap FieldLabel class
29744 * @cfg {String} html contents of the element
29745 * @cfg {String} tag tag of the element default label
29746 * @cfg {String} cls class of the element
29747 * @cfg {String} target label target
29748 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29749 * @cfg {String} invalidClass default "text-warning"
29750 * @cfg {String} validClass default "text-success"
29751 * @cfg {String} iconTooltip default "This field is required"
29752 * @cfg {String} indicatorpos (left|right) default left
29755 * Create a new FieldLabel
29756 * @param {Object} config The config object
29759 Roo.bootstrap.FieldLabel = function(config){
29760 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29765 * Fires after the field has been marked as invalid.
29766 * @param {Roo.form.FieldLabel} this
29767 * @param {String} msg The validation message
29772 * Fires after the field has been validated with no errors.
29773 * @param {Roo.form.FieldLabel} this
29779 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29786 invalidClass : 'has-warning',
29787 validClass : 'has-success',
29788 iconTooltip : 'This field is required',
29789 indicatorpos : 'left',
29791 getAutoCreate : function(){
29795 cls : 'roo-bootstrap-field-label ' + this.cls,
29800 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29801 tooltip : this.iconTooltip
29810 if(this.indicatorpos == 'right'){
29813 cls : 'roo-bootstrap-field-label ' + this.cls,
29822 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29823 tooltip : this.iconTooltip
29832 initEvents: function()
29834 Roo.bootstrap.Element.superclass.initEvents.call(this);
29836 this.indicator = this.indicatorEl();
29838 if(this.indicator){
29839 this.indicator.removeClass('visible');
29840 this.indicator.addClass('invisible');
29843 Roo.bootstrap.FieldLabel.register(this);
29846 indicatorEl : function()
29848 var indicator = this.el.select('i.roo-required-indicator',true).first();
29859 * Mark this field as valid
29861 markValid : function()
29863 if(this.indicator){
29864 this.indicator.removeClass('visible');
29865 this.indicator.addClass('invisible');
29868 this.el.removeClass(this.invalidClass);
29870 this.el.addClass(this.validClass);
29872 this.fireEvent('valid', this);
29876 * Mark this field as invalid
29877 * @param {String} msg The validation message
29879 markInvalid : function(msg)
29881 if(this.indicator){
29882 this.indicator.removeClass('invisible');
29883 this.indicator.addClass('visible');
29886 this.el.removeClass(this.validClass);
29888 this.el.addClass(this.invalidClass);
29890 this.fireEvent('invalid', this, msg);
29896 Roo.apply(Roo.bootstrap.FieldLabel, {
29901 * register a FieldLabel Group
29902 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29904 register : function(label)
29906 if(this.groups.hasOwnProperty(label.target)){
29910 this.groups[label.target] = label;
29914 * fetch a FieldLabel Group based on the target
29915 * @param {string} target
29916 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29918 get: function(target) {
29919 if (typeof(this.groups[target]) == 'undefined') {
29923 return this.groups[target] ;
29932 * page DateSplitField.
29938 * @class Roo.bootstrap.DateSplitField
29939 * @extends Roo.bootstrap.Component
29940 * Bootstrap DateSplitField class
29941 * @cfg {string} fieldLabel - the label associated
29942 * @cfg {Number} labelWidth set the width of label (0-12)
29943 * @cfg {String} labelAlign (top|left)
29944 * @cfg {Boolean} dayAllowBlank (true|false) default false
29945 * @cfg {Boolean} monthAllowBlank (true|false) default false
29946 * @cfg {Boolean} yearAllowBlank (true|false) default false
29947 * @cfg {string} dayPlaceholder
29948 * @cfg {string} monthPlaceholder
29949 * @cfg {string} yearPlaceholder
29950 * @cfg {string} dayFormat default 'd'
29951 * @cfg {string} monthFormat default 'm'
29952 * @cfg {string} yearFormat default 'Y'
29953 * @cfg {Number} labellg set the width of label (1-12)
29954 * @cfg {Number} labelmd set the width of label (1-12)
29955 * @cfg {Number} labelsm set the width of label (1-12)
29956 * @cfg {Number} labelxs set the width of label (1-12)
29960 * Create a new DateSplitField
29961 * @param {Object} config The config object
29964 Roo.bootstrap.DateSplitField = function(config){
29965 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29971 * getting the data of years
29972 * @param {Roo.bootstrap.DateSplitField} this
29973 * @param {Object} years
29978 * getting the data of days
29979 * @param {Roo.bootstrap.DateSplitField} this
29980 * @param {Object} days
29985 * Fires after the field has been marked as invalid.
29986 * @param {Roo.form.Field} this
29987 * @param {String} msg The validation message
29992 * Fires after the field has been validated with no errors.
29993 * @param {Roo.form.Field} this
29999 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30002 labelAlign : 'top',
30004 dayAllowBlank : false,
30005 monthAllowBlank : false,
30006 yearAllowBlank : false,
30007 dayPlaceholder : '',
30008 monthPlaceholder : '',
30009 yearPlaceholder : '',
30013 isFormField : true,
30019 getAutoCreate : function()
30023 cls : 'row roo-date-split-field-group',
30028 cls : 'form-hidden-field roo-date-split-field-group-value',
30034 var labelCls = 'col-md-12';
30035 var contentCls = 'col-md-4';
30037 if(this.fieldLabel){
30041 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30045 html : this.fieldLabel
30050 if(this.labelAlign == 'left'){
30052 if(this.labelWidth > 12){
30053 label.style = "width: " + this.labelWidth + 'px';
30056 if(this.labelWidth < 13 && this.labelmd == 0){
30057 this.labelmd = this.labelWidth;
30060 if(this.labellg > 0){
30061 labelCls = ' col-lg-' + this.labellg;
30062 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30065 if(this.labelmd > 0){
30066 labelCls = ' col-md-' + this.labelmd;
30067 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30070 if(this.labelsm > 0){
30071 labelCls = ' col-sm-' + this.labelsm;
30072 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30075 if(this.labelxs > 0){
30076 labelCls = ' col-xs-' + this.labelxs;
30077 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30081 label.cls += ' ' + labelCls;
30083 cfg.cn.push(label);
30086 Roo.each(['day', 'month', 'year'], function(t){
30089 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30096 inputEl: function ()
30098 return this.el.select('.roo-date-split-field-group-value', true).first();
30101 onRender : function(ct, position)
30105 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30107 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30109 this.dayField = new Roo.bootstrap.ComboBox({
30110 allowBlank : this.dayAllowBlank,
30111 alwaysQuery : true,
30112 displayField : 'value',
30115 forceSelection : true,
30117 placeholder : this.dayPlaceholder,
30118 selectOnFocus : true,
30119 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30120 triggerAction : 'all',
30122 valueField : 'value',
30123 store : new Roo.data.SimpleStore({
30124 data : (function() {
30126 _this.fireEvent('days', _this, days);
30129 fields : [ 'value' ]
30132 select : function (_self, record, index)
30134 _this.setValue(_this.getValue());
30139 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30141 this.monthField = new Roo.bootstrap.MonthField({
30142 after : '<i class=\"fa fa-calendar\"></i>',
30143 allowBlank : this.monthAllowBlank,
30144 placeholder : this.monthPlaceholder,
30147 render : function (_self)
30149 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30150 e.preventDefault();
30154 select : function (_self, oldvalue, newvalue)
30156 _this.setValue(_this.getValue());
30161 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30163 this.yearField = new Roo.bootstrap.ComboBox({
30164 allowBlank : this.yearAllowBlank,
30165 alwaysQuery : true,
30166 displayField : 'value',
30169 forceSelection : true,
30171 placeholder : this.yearPlaceholder,
30172 selectOnFocus : true,
30173 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30174 triggerAction : 'all',
30176 valueField : 'value',
30177 store : new Roo.data.SimpleStore({
30178 data : (function() {
30180 _this.fireEvent('years', _this, years);
30183 fields : [ 'value' ]
30186 select : function (_self, record, index)
30188 _this.setValue(_this.getValue());
30193 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30196 setValue : function(v, format)
30198 this.inputEl.dom.value = v;
30200 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30202 var d = Date.parseDate(v, f);
30209 this.setDay(d.format(this.dayFormat));
30210 this.setMonth(d.format(this.monthFormat));
30211 this.setYear(d.format(this.yearFormat));
30218 setDay : function(v)
30220 this.dayField.setValue(v);
30221 this.inputEl.dom.value = this.getValue();
30226 setMonth : function(v)
30228 this.monthField.setValue(v, true);
30229 this.inputEl.dom.value = this.getValue();
30234 setYear : function(v)
30236 this.yearField.setValue(v);
30237 this.inputEl.dom.value = this.getValue();
30242 getDay : function()
30244 return this.dayField.getValue();
30247 getMonth : function()
30249 return this.monthField.getValue();
30252 getYear : function()
30254 return this.yearField.getValue();
30257 getValue : function()
30259 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30261 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30271 this.inputEl.dom.value = '';
30276 validate : function()
30278 var d = this.dayField.validate();
30279 var m = this.monthField.validate();
30280 var y = this.yearField.validate();
30285 (!this.dayAllowBlank && !d) ||
30286 (!this.monthAllowBlank && !m) ||
30287 (!this.yearAllowBlank && !y)
30292 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30301 this.markInvalid();
30306 markValid : function()
30309 var label = this.el.select('label', true).first();
30310 var icon = this.el.select('i.fa-star', true).first();
30316 this.fireEvent('valid', this);
30320 * Mark this field as invalid
30321 * @param {String} msg The validation message
30323 markInvalid : function(msg)
30326 var label = this.el.select('label', true).first();
30327 var icon = this.el.select('i.fa-star', true).first();
30329 if(label && !icon){
30330 this.el.select('.roo-date-split-field-label', true).createChild({
30332 cls : 'text-danger fa fa-lg fa-star',
30333 tooltip : 'This field is required',
30334 style : 'margin-right:5px;'
30338 this.fireEvent('invalid', this, msg);
30341 clearInvalid : function()
30343 var label = this.el.select('label', true).first();
30344 var icon = this.el.select('i.fa-star', true).first();
30350 this.fireEvent('valid', this);
30353 getName: function()
30363 * http://masonry.desandro.com
30365 * The idea is to render all the bricks based on vertical width...
30367 * The original code extends 'outlayer' - we might need to use that....
30373 * @class Roo.bootstrap.LayoutMasonry
30374 * @extends Roo.bootstrap.Component
30375 * Bootstrap Layout Masonry class
30378 * Create a new Element
30379 * @param {Object} config The config object
30382 Roo.bootstrap.LayoutMasonry = function(config){
30384 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30388 Roo.bootstrap.LayoutMasonry.register(this);
30394 * Fire after layout the items
30395 * @param {Roo.bootstrap.LayoutMasonry} this
30396 * @param {Roo.EventObject} e
30403 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30406 * @cfg {Boolean} isLayoutInstant = no animation?
30408 isLayoutInstant : false, // needed?
30411 * @cfg {Number} boxWidth width of the columns
30416 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30421 * @cfg {Number} padWidth padding below box..
30426 * @cfg {Number} gutter gutter width..
30431 * @cfg {Number} maxCols maximum number of columns
30437 * @cfg {Boolean} isAutoInitial defalut true
30439 isAutoInitial : true,
30444 * @cfg {Boolean} isHorizontal defalut false
30446 isHorizontal : false,
30448 currentSize : null,
30454 bricks: null, //CompositeElement
30458 _isLayoutInited : false,
30460 // isAlternative : false, // only use for vertical layout...
30463 * @cfg {Number} alternativePadWidth padding below box..
30465 alternativePadWidth : 50,
30467 selectedBrick : [],
30469 getAutoCreate : function(){
30471 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30475 cls: 'blog-masonary-wrapper ' + this.cls,
30477 cls : 'mas-boxes masonary'
30484 getChildContainer: function( )
30486 if (this.boxesEl) {
30487 return this.boxesEl;
30490 this.boxesEl = this.el.select('.mas-boxes').first();
30492 return this.boxesEl;
30496 initEvents : function()
30500 if(this.isAutoInitial){
30501 Roo.log('hook children rendered');
30502 this.on('childrenrendered', function() {
30503 Roo.log('children rendered');
30509 initial : function()
30511 this.selectedBrick = [];
30513 this.currentSize = this.el.getBox(true);
30515 Roo.EventManager.onWindowResize(this.resize, this);
30517 if(!this.isAutoInitial){
30525 //this.layout.defer(500,this);
30529 resize : function()
30531 var cs = this.el.getBox(true);
30534 this.currentSize.width == cs.width &&
30535 this.currentSize.x == cs.x &&
30536 this.currentSize.height == cs.height &&
30537 this.currentSize.y == cs.y
30539 Roo.log("no change in with or X or Y");
30543 this.currentSize = cs;
30549 layout : function()
30551 this._resetLayout();
30553 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30555 this.layoutItems( isInstant );
30557 this._isLayoutInited = true;
30559 this.fireEvent('layout', this);
30563 _resetLayout : function()
30565 if(this.isHorizontal){
30566 this.horizontalMeasureColumns();
30570 this.verticalMeasureColumns();
30574 verticalMeasureColumns : function()
30576 this.getContainerWidth();
30578 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30579 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30583 var boxWidth = this.boxWidth + this.padWidth;
30585 if(this.containerWidth < this.boxWidth){
30586 boxWidth = this.containerWidth
30589 var containerWidth = this.containerWidth;
30591 var cols = Math.floor(containerWidth / boxWidth);
30593 this.cols = Math.max( cols, 1 );
30595 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30597 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30599 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30601 this.colWidth = boxWidth + avail - this.padWidth;
30603 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30604 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30607 horizontalMeasureColumns : function()
30609 this.getContainerWidth();
30611 var boxWidth = this.boxWidth;
30613 if(this.containerWidth < boxWidth){
30614 boxWidth = this.containerWidth;
30617 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30619 this.el.setHeight(boxWidth);
30623 getContainerWidth : function()
30625 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30628 layoutItems : function( isInstant )
30630 Roo.log(this.bricks);
30632 var items = Roo.apply([], this.bricks);
30634 if(this.isHorizontal){
30635 this._horizontalLayoutItems( items , isInstant );
30639 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30640 // this._verticalAlternativeLayoutItems( items , isInstant );
30644 this._verticalLayoutItems( items , isInstant );
30648 _verticalLayoutItems : function ( items , isInstant)
30650 if ( !items || !items.length ) {
30655 ['xs', 'xs', 'xs', 'tall'],
30656 ['xs', 'xs', 'tall'],
30657 ['xs', 'xs', 'sm'],
30658 ['xs', 'xs', 'xs'],
30664 ['sm', 'xs', 'xs'],
30668 ['tall', 'xs', 'xs', 'xs'],
30669 ['tall', 'xs', 'xs'],
30681 Roo.each(items, function(item, k){
30683 switch (item.size) {
30684 // these layouts take up a full box,
30695 boxes.push([item]);
30718 var filterPattern = function(box, length)
30726 var pattern = box.slice(0, length);
30730 Roo.each(pattern, function(i){
30731 format.push(i.size);
30734 Roo.each(standard, function(s){
30736 if(String(s) != String(format)){
30745 if(!match && length == 1){
30750 filterPattern(box, length - 1);
30754 queue.push(pattern);
30756 box = box.slice(length, box.length);
30758 filterPattern(box, 4);
30764 Roo.each(boxes, function(box, k){
30770 if(box.length == 1){
30775 filterPattern(box, 4);
30779 this._processVerticalLayoutQueue( queue, isInstant );
30783 // _verticalAlternativeLayoutItems : function( items , isInstant )
30785 // if ( !items || !items.length ) {
30789 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30793 _horizontalLayoutItems : function ( items , isInstant)
30795 if ( !items || !items.length || items.length < 3) {
30801 var eItems = items.slice(0, 3);
30803 items = items.slice(3, items.length);
30806 ['xs', 'xs', 'xs', 'wide'],
30807 ['xs', 'xs', 'wide'],
30808 ['xs', 'xs', 'sm'],
30809 ['xs', 'xs', 'xs'],
30815 ['sm', 'xs', 'xs'],
30819 ['wide', 'xs', 'xs', 'xs'],
30820 ['wide', 'xs', 'xs'],
30833 Roo.each(items, function(item, k){
30835 switch (item.size) {
30846 boxes.push([item]);
30870 var filterPattern = function(box, length)
30878 var pattern = box.slice(0, length);
30882 Roo.each(pattern, function(i){
30883 format.push(i.size);
30886 Roo.each(standard, function(s){
30888 if(String(s) != String(format)){
30897 if(!match && length == 1){
30902 filterPattern(box, length - 1);
30906 queue.push(pattern);
30908 box = box.slice(length, box.length);
30910 filterPattern(box, 4);
30916 Roo.each(boxes, function(box, k){
30922 if(box.length == 1){
30927 filterPattern(box, 4);
30934 var pos = this.el.getBox(true);
30938 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30940 var hit_end = false;
30942 Roo.each(queue, function(box){
30946 Roo.each(box, function(b){
30948 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30958 Roo.each(box, function(b){
30960 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30963 mx = Math.max(mx, b.x);
30967 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30971 Roo.each(box, function(b){
30973 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30987 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30990 /** Sets position of item in DOM
30991 * @param {Element} item
30992 * @param {Number} x - horizontal position
30993 * @param {Number} y - vertical position
30994 * @param {Boolean} isInstant - disables transitions
30996 _processVerticalLayoutQueue : function( queue, isInstant )
30998 var pos = this.el.getBox(true);
31003 for (var i = 0; i < this.cols; i++){
31007 Roo.each(queue, function(box, k){
31009 var col = k % this.cols;
31011 Roo.each(box, function(b,kk){
31013 b.el.position('absolute');
31015 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31016 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31018 if(b.size == 'md-left' || b.size == 'md-right'){
31019 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31020 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31023 b.el.setWidth(width);
31024 b.el.setHeight(height);
31026 b.el.select('iframe',true).setSize(width,height);
31030 for (var i = 0; i < this.cols; i++){
31032 if(maxY[i] < maxY[col]){
31037 col = Math.min(col, i);
31041 x = pos.x + col * (this.colWidth + this.padWidth);
31045 var positions = [];
31047 switch (box.length){
31049 positions = this.getVerticalOneBoxColPositions(x, y, box);
31052 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31055 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31058 positions = this.getVerticalFourBoxColPositions(x, y, box);
31064 Roo.each(box, function(b,kk){
31066 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31068 var sz = b.el.getSize();
31070 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31078 for (var i = 0; i < this.cols; i++){
31079 mY = Math.max(mY, maxY[i]);
31082 this.el.setHeight(mY - pos.y);
31086 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31088 // var pos = this.el.getBox(true);
31091 // var maxX = pos.right;
31093 // var maxHeight = 0;
31095 // Roo.each(items, function(item, k){
31099 // item.el.position('absolute');
31101 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31103 // item.el.setWidth(width);
31105 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31107 // item.el.setHeight(height);
31110 // item.el.setXY([x, y], isInstant ? false : true);
31112 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31115 // y = y + height + this.alternativePadWidth;
31117 // maxHeight = maxHeight + height + this.alternativePadWidth;
31121 // this.el.setHeight(maxHeight);
31125 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31127 var pos = this.el.getBox(true);
31132 var maxX = pos.right;
31134 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31136 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31138 Roo.each(queue, function(box, k){
31140 Roo.each(box, function(b, kk){
31142 b.el.position('absolute');
31144 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31145 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31147 if(b.size == 'md-left' || b.size == 'md-right'){
31148 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31149 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31152 b.el.setWidth(width);
31153 b.el.setHeight(height);
31161 var positions = [];
31163 switch (box.length){
31165 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31168 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31171 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31174 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31180 Roo.each(box, function(b,kk){
31182 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31184 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31192 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31194 Roo.each(eItems, function(b,k){
31196 b.size = (k == 0) ? 'sm' : 'xs';
31197 b.x = (k == 0) ? 2 : 1;
31198 b.y = (k == 0) ? 2 : 1;
31200 b.el.position('absolute');
31202 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31204 b.el.setWidth(width);
31206 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31208 b.el.setHeight(height);
31212 var positions = [];
31215 x : maxX - this.unitWidth * 2 - this.gutter,
31220 x : maxX - this.unitWidth,
31221 y : minY + (this.unitWidth + this.gutter) * 2
31225 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31229 Roo.each(eItems, function(b,k){
31231 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31237 getVerticalOneBoxColPositions : function(x, y, box)
31241 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31243 if(box[0].size == 'md-left'){
31247 if(box[0].size == 'md-right'){
31252 x : x + (this.unitWidth + this.gutter) * rand,
31259 getVerticalTwoBoxColPositions : function(x, y, box)
31263 if(box[0].size == 'xs'){
31267 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31271 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31285 x : x + (this.unitWidth + this.gutter) * 2,
31286 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31293 getVerticalThreeBoxColPositions : function(x, y, box)
31297 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31305 x : x + (this.unitWidth + this.gutter) * 1,
31310 x : x + (this.unitWidth + this.gutter) * 2,
31318 if(box[0].size == 'xs' && box[1].size == 'xs'){
31327 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31331 x : x + (this.unitWidth + this.gutter) * 1,
31345 x : x + (this.unitWidth + this.gutter) * 2,
31350 x : x + (this.unitWidth + this.gutter) * 2,
31351 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31358 getVerticalFourBoxColPositions : function(x, y, box)
31362 if(box[0].size == 'xs'){
31371 y : y + (this.unitHeight + this.gutter) * 1
31376 y : y + (this.unitHeight + this.gutter) * 2
31380 x : x + (this.unitWidth + this.gutter) * 1,
31394 x : x + (this.unitWidth + this.gutter) * 2,
31399 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31400 y : y + (this.unitHeight + this.gutter) * 1
31404 x : x + (this.unitWidth + this.gutter) * 2,
31405 y : y + (this.unitWidth + this.gutter) * 2
31412 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31416 if(box[0].size == 'md-left'){
31418 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31425 if(box[0].size == 'md-right'){
31427 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31428 y : minY + (this.unitWidth + this.gutter) * 1
31434 var rand = Math.floor(Math.random() * (4 - box[0].y));
31437 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31438 y : minY + (this.unitWidth + this.gutter) * rand
31445 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31449 if(box[0].size == 'xs'){
31452 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31457 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31458 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31466 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31471 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31472 y : minY + (this.unitWidth + this.gutter) * 2
31479 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31483 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31486 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31491 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31492 y : minY + (this.unitWidth + this.gutter) * 1
31496 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31497 y : minY + (this.unitWidth + this.gutter) * 2
31504 if(box[0].size == 'xs' && box[1].size == 'xs'){
31507 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31512 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31517 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31518 y : minY + (this.unitWidth + this.gutter) * 1
31526 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31531 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31532 y : minY + (this.unitWidth + this.gutter) * 2
31536 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31537 y : minY + (this.unitWidth + this.gutter) * 2
31544 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31548 if(box[0].size == 'xs'){
31551 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31556 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31561 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),
31566 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31567 y : minY + (this.unitWidth + this.gutter) * 1
31575 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31580 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31581 y : minY + (this.unitWidth + this.gutter) * 2
31585 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31586 y : minY + (this.unitWidth + this.gutter) * 2
31590 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),
31591 y : minY + (this.unitWidth + this.gutter) * 2
31599 * remove a Masonry Brick
31600 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31602 removeBrick : function(brick_id)
31608 for (var i = 0; i<this.bricks.length; i++) {
31609 if (this.bricks[i].id == brick_id) {
31610 this.bricks.splice(i,1);
31611 this.el.dom.removeChild(Roo.get(brick_id).dom);
31618 * adds a Masonry Brick
31619 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31621 addBrick : function(cfg)
31623 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31624 //this.register(cn);
31625 cn.parentId = this.id;
31626 cn.onRender(this.el, null);
31631 * register a Masonry Brick
31632 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31635 register : function(brick)
31637 this.bricks.push(brick);
31638 brick.masonryId = this.id;
31642 * clear all the Masonry Brick
31644 clearAll : function()
31647 //this.getChildContainer().dom.innerHTML = "";
31648 this.el.dom.innerHTML = '';
31651 getSelected : function()
31653 if (!this.selectedBrick) {
31657 return this.selectedBrick;
31661 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31665 * register a Masonry Layout
31666 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31669 register : function(layout)
31671 this.groups[layout.id] = layout;
31674 * fetch a Masonry Layout based on the masonry layout ID
31675 * @param {string} the masonry layout to add
31676 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31679 get: function(layout_id) {
31680 if (typeof(this.groups[layout_id]) == 'undefined') {
31683 return this.groups[layout_id] ;
31695 * http://masonry.desandro.com
31697 * The idea is to render all the bricks based on vertical width...
31699 * The original code extends 'outlayer' - we might need to use that....
31705 * @class Roo.bootstrap.LayoutMasonryAuto
31706 * @extends Roo.bootstrap.Component
31707 * Bootstrap Layout Masonry class
31710 * Create a new Element
31711 * @param {Object} config The config object
31714 Roo.bootstrap.LayoutMasonryAuto = function(config){
31715 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31718 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31721 * @cfg {Boolean} isFitWidth - resize the width..
31723 isFitWidth : false, // options..
31725 * @cfg {Boolean} isOriginLeft = left align?
31727 isOriginLeft : true,
31729 * @cfg {Boolean} isOriginTop = top align?
31731 isOriginTop : false,
31733 * @cfg {Boolean} isLayoutInstant = no animation?
31735 isLayoutInstant : false, // needed?
31737 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31739 isResizingContainer : true,
31741 * @cfg {Number} columnWidth width of the columns
31747 * @cfg {Number} maxCols maximum number of columns
31752 * @cfg {Number} padHeight padding below box..
31758 * @cfg {Boolean} isAutoInitial defalut true
31761 isAutoInitial : true,
31767 initialColumnWidth : 0,
31768 currentSize : null,
31770 colYs : null, // array.
31777 bricks: null, //CompositeElement
31778 cols : 0, // array?
31779 // element : null, // wrapped now this.el
31780 _isLayoutInited : null,
31783 getAutoCreate : function(){
31787 cls: 'blog-masonary-wrapper ' + this.cls,
31789 cls : 'mas-boxes masonary'
31796 getChildContainer: function( )
31798 if (this.boxesEl) {
31799 return this.boxesEl;
31802 this.boxesEl = this.el.select('.mas-boxes').first();
31804 return this.boxesEl;
31808 initEvents : function()
31812 if(this.isAutoInitial){
31813 Roo.log('hook children rendered');
31814 this.on('childrenrendered', function() {
31815 Roo.log('children rendered');
31822 initial : function()
31824 this.reloadItems();
31826 this.currentSize = this.el.getBox(true);
31828 /// was window resize... - let's see if this works..
31829 Roo.EventManager.onWindowResize(this.resize, this);
31831 if(!this.isAutoInitial){
31836 this.layout.defer(500,this);
31839 reloadItems: function()
31841 this.bricks = this.el.select('.masonry-brick', true);
31843 this.bricks.each(function(b) {
31844 //Roo.log(b.getSize());
31845 if (!b.attr('originalwidth')) {
31846 b.attr('originalwidth', b.getSize().width);
31851 Roo.log(this.bricks.elements.length);
31854 resize : function()
31857 var cs = this.el.getBox(true);
31859 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31860 Roo.log("no change in with or X");
31863 this.currentSize = cs;
31867 layout : function()
31870 this._resetLayout();
31871 //this._manageStamps();
31873 // don't animate first layout
31874 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31875 this.layoutItems( isInstant );
31877 // flag for initalized
31878 this._isLayoutInited = true;
31881 layoutItems : function( isInstant )
31883 //var items = this._getItemsForLayout( this.items );
31884 // original code supports filtering layout items.. we just ignore it..
31886 this._layoutItems( this.bricks , isInstant );
31888 this._postLayout();
31890 _layoutItems : function ( items , isInstant)
31892 //this.fireEvent( 'layout', this, items );
31895 if ( !items || !items.elements.length ) {
31896 // no items, emit event with empty array
31901 items.each(function(item) {
31902 Roo.log("layout item");
31904 // get x/y object from method
31905 var position = this._getItemLayoutPosition( item );
31907 position.item = item;
31908 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31909 queue.push( position );
31912 this._processLayoutQueue( queue );
31914 /** Sets position of item in DOM
31915 * @param {Element} item
31916 * @param {Number} x - horizontal position
31917 * @param {Number} y - vertical position
31918 * @param {Boolean} isInstant - disables transitions
31920 _processLayoutQueue : function( queue )
31922 for ( var i=0, len = queue.length; i < len; i++ ) {
31923 var obj = queue[i];
31924 obj.item.position('absolute');
31925 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31931 * Any logic you want to do after each layout,
31932 * i.e. size the container
31934 _postLayout : function()
31936 this.resizeContainer();
31939 resizeContainer : function()
31941 if ( !this.isResizingContainer ) {
31944 var size = this._getContainerSize();
31946 this.el.setSize(size.width,size.height);
31947 this.boxesEl.setSize(size.width,size.height);
31953 _resetLayout : function()
31955 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31956 this.colWidth = this.el.getWidth();
31957 //this.gutter = this.el.getWidth();
31959 this.measureColumns();
31965 this.colYs.push( 0 );
31971 measureColumns : function()
31973 this.getContainerWidth();
31974 // if columnWidth is 0, default to outerWidth of first item
31975 if ( !this.columnWidth ) {
31976 var firstItem = this.bricks.first();
31977 Roo.log(firstItem);
31978 this.columnWidth = this.containerWidth;
31979 if (firstItem && firstItem.attr('originalwidth') ) {
31980 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31982 // columnWidth fall back to item of first element
31983 Roo.log("set column width?");
31984 this.initialColumnWidth = this.columnWidth ;
31986 // if first elem has no width, default to size of container
31991 if (this.initialColumnWidth) {
31992 this.columnWidth = this.initialColumnWidth;
31997 // column width is fixed at the top - however if container width get's smaller we should
32000 // this bit calcs how man columns..
32002 var columnWidth = this.columnWidth += this.gutter;
32004 // calculate columns
32005 var containerWidth = this.containerWidth + this.gutter;
32007 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32008 // fix rounding errors, typically with gutters
32009 var excess = columnWidth - containerWidth % columnWidth;
32012 // if overshoot is less than a pixel, round up, otherwise floor it
32013 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32014 cols = Math[ mathMethod ]( cols );
32015 this.cols = Math.max( cols, 1 );
32016 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32018 // padding positioning..
32019 var totalColWidth = this.cols * this.columnWidth;
32020 var padavail = this.containerWidth - totalColWidth;
32021 // so for 2 columns - we need 3 'pads'
32023 var padNeeded = (1+this.cols) * this.padWidth;
32025 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32027 this.columnWidth += padExtra
32028 //this.padWidth = Math.floor(padavail / ( this.cols));
32030 // adjust colum width so that padding is fixed??
32032 // we have 3 columns ... total = width * 3
32033 // we have X left over... that should be used by
32035 //if (this.expandC) {
32043 getContainerWidth : function()
32045 /* // container is parent if fit width
32046 var container = this.isFitWidth ? this.element.parentNode : this.element;
32047 // check that this.size and size are there
32048 // IE8 triggers resize on body size change, so they might not be
32050 var size = getSize( container ); //FIXME
32051 this.containerWidth = size && size.innerWidth; //FIXME
32054 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32058 _getItemLayoutPosition : function( item ) // what is item?
32060 // we resize the item to our columnWidth..
32062 item.setWidth(this.columnWidth);
32063 item.autoBoxAdjust = false;
32065 var sz = item.getSize();
32067 // how many columns does this brick span
32068 var remainder = this.containerWidth % this.columnWidth;
32070 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32071 // round if off by 1 pixel, otherwise use ceil
32072 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32073 colSpan = Math.min( colSpan, this.cols );
32075 // normally this should be '1' as we dont' currently allow multi width columns..
32077 var colGroup = this._getColGroup( colSpan );
32078 // get the minimum Y value from the columns
32079 var minimumY = Math.min.apply( Math, colGroup );
32080 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32082 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32084 // position the brick
32086 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32087 y: this.currentSize.y + minimumY + this.padHeight
32091 // apply setHeight to necessary columns
32092 var setHeight = minimumY + sz.height + this.padHeight;
32093 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32095 var setSpan = this.cols + 1 - colGroup.length;
32096 for ( var i = 0; i < setSpan; i++ ) {
32097 this.colYs[ shortColIndex + i ] = setHeight ;
32104 * @param {Number} colSpan - number of columns the element spans
32105 * @returns {Array} colGroup
32107 _getColGroup : function( colSpan )
32109 if ( colSpan < 2 ) {
32110 // if brick spans only one column, use all the column Ys
32115 // how many different places could this brick fit horizontally
32116 var groupCount = this.cols + 1 - colSpan;
32117 // for each group potential horizontal position
32118 for ( var i = 0; i < groupCount; i++ ) {
32119 // make an array of colY values for that one group
32120 var groupColYs = this.colYs.slice( i, i + colSpan );
32121 // and get the max value of the array
32122 colGroup[i] = Math.max.apply( Math, groupColYs );
32127 _manageStamp : function( stamp )
32129 var stampSize = stamp.getSize();
32130 var offset = stamp.getBox();
32131 // get the columns that this stamp affects
32132 var firstX = this.isOriginLeft ? offset.x : offset.right;
32133 var lastX = firstX + stampSize.width;
32134 var firstCol = Math.floor( firstX / this.columnWidth );
32135 firstCol = Math.max( 0, firstCol );
32137 var lastCol = Math.floor( lastX / this.columnWidth );
32138 // lastCol should not go over if multiple of columnWidth #425
32139 lastCol -= lastX % this.columnWidth ? 0 : 1;
32140 lastCol = Math.min( this.cols - 1, lastCol );
32142 // set colYs to bottom of the stamp
32143 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32146 for ( var i = firstCol; i <= lastCol; i++ ) {
32147 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32152 _getContainerSize : function()
32154 this.maxY = Math.max.apply( Math, this.colYs );
32159 if ( this.isFitWidth ) {
32160 size.width = this._getContainerFitWidth();
32166 _getContainerFitWidth : function()
32168 var unusedCols = 0;
32169 // count unused columns
32172 if ( this.colYs[i] !== 0 ) {
32177 // fit container to columns that have been used
32178 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32181 needsResizeLayout : function()
32183 var previousWidth = this.containerWidth;
32184 this.getContainerWidth();
32185 return previousWidth !== this.containerWidth;
32200 * @class Roo.bootstrap.MasonryBrick
32201 * @extends Roo.bootstrap.Component
32202 * Bootstrap MasonryBrick class
32205 * Create a new MasonryBrick
32206 * @param {Object} config The config object
32209 Roo.bootstrap.MasonryBrick = function(config){
32211 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32213 Roo.bootstrap.MasonryBrick.register(this);
32219 * When a MasonryBrick is clcik
32220 * @param {Roo.bootstrap.MasonryBrick} this
32221 * @param {Roo.EventObject} e
32227 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32230 * @cfg {String} title
32234 * @cfg {String} html
32238 * @cfg {String} bgimage
32242 * @cfg {String} videourl
32246 * @cfg {String} cls
32250 * @cfg {String} href
32254 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32259 * @cfg {String} placetitle (center|bottom)
32264 * @cfg {Boolean} isFitContainer defalut true
32266 isFitContainer : true,
32269 * @cfg {Boolean} preventDefault defalut false
32271 preventDefault : false,
32274 * @cfg {Boolean} inverse defalut false
32276 maskInverse : false,
32278 getAutoCreate : function()
32280 if(!this.isFitContainer){
32281 return this.getSplitAutoCreate();
32284 var cls = 'masonry-brick masonry-brick-full';
32286 if(this.href.length){
32287 cls += ' masonry-brick-link';
32290 if(this.bgimage.length){
32291 cls += ' masonry-brick-image';
32294 if(this.maskInverse){
32295 cls += ' mask-inverse';
32298 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32299 cls += ' enable-mask';
32303 cls += ' masonry-' + this.size + '-brick';
32306 if(this.placetitle.length){
32308 switch (this.placetitle) {
32310 cls += ' masonry-center-title';
32313 cls += ' masonry-bottom-title';
32320 if(!this.html.length && !this.bgimage.length){
32321 cls += ' masonry-center-title';
32324 if(!this.html.length && this.bgimage.length){
32325 cls += ' masonry-bottom-title';
32330 cls += ' ' + this.cls;
32334 tag: (this.href.length) ? 'a' : 'div',
32339 cls: 'masonry-brick-mask'
32343 cls: 'masonry-brick-paragraph',
32349 if(this.href.length){
32350 cfg.href = this.href;
32353 var cn = cfg.cn[1].cn;
32355 if(this.title.length){
32358 cls: 'masonry-brick-title',
32363 if(this.html.length){
32366 cls: 'masonry-brick-text',
32371 if (!this.title.length && !this.html.length) {
32372 cfg.cn[1].cls += ' hide';
32375 if(this.bgimage.length){
32378 cls: 'masonry-brick-image-view',
32383 if(this.videourl.length){
32384 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32385 // youtube support only?
32388 cls: 'masonry-brick-image-view',
32391 allowfullscreen : true
32399 getSplitAutoCreate : function()
32401 var cls = 'masonry-brick masonry-brick-split';
32403 if(this.href.length){
32404 cls += ' masonry-brick-link';
32407 if(this.bgimage.length){
32408 cls += ' masonry-brick-image';
32412 cls += ' masonry-' + this.size + '-brick';
32415 switch (this.placetitle) {
32417 cls += ' masonry-center-title';
32420 cls += ' masonry-bottom-title';
32423 if(!this.bgimage.length){
32424 cls += ' masonry-center-title';
32427 if(this.bgimage.length){
32428 cls += ' masonry-bottom-title';
32434 cls += ' ' + this.cls;
32438 tag: (this.href.length) ? 'a' : 'div',
32443 cls: 'masonry-brick-split-head',
32447 cls: 'masonry-brick-paragraph',
32454 cls: 'masonry-brick-split-body',
32460 if(this.href.length){
32461 cfg.href = this.href;
32464 if(this.title.length){
32465 cfg.cn[0].cn[0].cn.push({
32467 cls: 'masonry-brick-title',
32472 if(this.html.length){
32473 cfg.cn[1].cn.push({
32475 cls: 'masonry-brick-text',
32480 if(this.bgimage.length){
32481 cfg.cn[0].cn.push({
32483 cls: 'masonry-brick-image-view',
32488 if(this.videourl.length){
32489 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32490 // youtube support only?
32491 cfg.cn[0].cn.cn.push({
32493 cls: 'masonry-brick-image-view',
32496 allowfullscreen : true
32503 initEvents: function()
32505 switch (this.size) {
32538 this.el.on('touchstart', this.onTouchStart, this);
32539 this.el.on('touchmove', this.onTouchMove, this);
32540 this.el.on('touchend', this.onTouchEnd, this);
32541 this.el.on('contextmenu', this.onContextMenu, this);
32543 this.el.on('mouseenter' ,this.enter, this);
32544 this.el.on('mouseleave', this.leave, this);
32545 this.el.on('click', this.onClick, this);
32548 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32549 this.parent().bricks.push(this);
32554 onClick: function(e, el)
32556 var time = this.endTimer - this.startTimer;
32557 // Roo.log(e.preventDefault());
32560 e.preventDefault();
32565 if(!this.preventDefault){
32569 e.preventDefault();
32571 if (this.activcClass != '') {
32572 this.selectBrick();
32575 this.fireEvent('click', this);
32578 enter: function(e, el)
32580 e.preventDefault();
32582 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32586 if(this.bgimage.length && this.html.length){
32587 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32591 leave: function(e, el)
32593 e.preventDefault();
32595 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32599 if(this.bgimage.length && this.html.length){
32600 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32604 onTouchStart: function(e, el)
32606 // e.preventDefault();
32608 this.touchmoved = false;
32610 if(!this.isFitContainer){
32614 if(!this.bgimage.length || !this.html.length){
32618 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32620 this.timer = new Date().getTime();
32624 onTouchMove: function(e, el)
32626 this.touchmoved = true;
32629 onContextMenu : function(e,el)
32631 e.preventDefault();
32632 e.stopPropagation();
32636 onTouchEnd: function(e, el)
32638 // e.preventDefault();
32640 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32647 if(!this.bgimage.length || !this.html.length){
32649 if(this.href.length){
32650 window.location.href = this.href;
32656 if(!this.isFitContainer){
32660 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32662 window.location.href = this.href;
32665 //selection on single brick only
32666 selectBrick : function() {
32668 if (!this.parentId) {
32672 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32673 var index = m.selectedBrick.indexOf(this.id);
32676 m.selectedBrick.splice(index,1);
32677 this.el.removeClass(this.activeClass);
32681 for(var i = 0; i < m.selectedBrick.length; i++) {
32682 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32683 b.el.removeClass(b.activeClass);
32686 m.selectedBrick = [];
32688 m.selectedBrick.push(this.id);
32689 this.el.addClass(this.activeClass);
32695 Roo.apply(Roo.bootstrap.MasonryBrick, {
32698 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32700 * register a Masonry Brick
32701 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32704 register : function(brick)
32706 //this.groups[brick.id] = brick;
32707 this.groups.add(brick.id, brick);
32710 * fetch a masonry brick based on the masonry brick ID
32711 * @param {string} the masonry brick to add
32712 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32715 get: function(brick_id)
32717 // if (typeof(this.groups[brick_id]) == 'undefined') {
32720 // return this.groups[brick_id] ;
32722 if(this.groups.key(brick_id)) {
32723 return this.groups.key(brick_id);
32741 * @class Roo.bootstrap.Brick
32742 * @extends Roo.bootstrap.Component
32743 * Bootstrap Brick class
32746 * Create a new Brick
32747 * @param {Object} config The config object
32750 Roo.bootstrap.Brick = function(config){
32751 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32757 * When a Brick is click
32758 * @param {Roo.bootstrap.Brick} this
32759 * @param {Roo.EventObject} e
32765 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32768 * @cfg {String} title
32772 * @cfg {String} html
32776 * @cfg {String} bgimage
32780 * @cfg {String} cls
32784 * @cfg {String} href
32788 * @cfg {String} video
32792 * @cfg {Boolean} square
32796 getAutoCreate : function()
32798 var cls = 'roo-brick';
32800 if(this.href.length){
32801 cls += ' roo-brick-link';
32804 if(this.bgimage.length){
32805 cls += ' roo-brick-image';
32808 if(!this.html.length && !this.bgimage.length){
32809 cls += ' roo-brick-center-title';
32812 if(!this.html.length && this.bgimage.length){
32813 cls += ' roo-brick-bottom-title';
32817 cls += ' ' + this.cls;
32821 tag: (this.href.length) ? 'a' : 'div',
32826 cls: 'roo-brick-paragraph',
32832 if(this.href.length){
32833 cfg.href = this.href;
32836 var cn = cfg.cn[0].cn;
32838 if(this.title.length){
32841 cls: 'roo-brick-title',
32846 if(this.html.length){
32849 cls: 'roo-brick-text',
32856 if(this.bgimage.length){
32859 cls: 'roo-brick-image-view',
32867 initEvents: function()
32869 if(this.title.length || this.html.length){
32870 this.el.on('mouseenter' ,this.enter, this);
32871 this.el.on('mouseleave', this.leave, this);
32874 Roo.EventManager.onWindowResize(this.resize, this);
32876 if(this.bgimage.length){
32877 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32878 this.imageEl.on('load', this.onImageLoad, this);
32885 onImageLoad : function()
32890 resize : function()
32892 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32894 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32896 if(this.bgimage.length){
32897 var image = this.el.select('.roo-brick-image-view', true).first();
32899 image.setWidth(paragraph.getWidth());
32902 image.setHeight(paragraph.getWidth());
32905 this.el.setHeight(image.getHeight());
32906 paragraph.setHeight(image.getHeight());
32912 enter: function(e, el)
32914 e.preventDefault();
32916 if(this.bgimage.length){
32917 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32918 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32922 leave: function(e, el)
32924 e.preventDefault();
32926 if(this.bgimage.length){
32927 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32928 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32944 * @class Roo.bootstrap.NumberField
32945 * @extends Roo.bootstrap.Input
32946 * Bootstrap NumberField class
32952 * Create a new NumberField
32953 * @param {Object} config The config object
32956 Roo.bootstrap.NumberField = function(config){
32957 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32960 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32963 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32965 allowDecimals : true,
32967 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32969 decimalSeparator : ".",
32971 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32973 decimalPrecision : 2,
32975 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32977 allowNegative : true,
32979 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32981 minValue : Number.NEGATIVE_INFINITY,
32983 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32985 maxValue : Number.MAX_VALUE,
32987 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32989 minText : "The minimum value for this field is {0}",
32991 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32993 maxText : "The maximum value for this field is {0}",
32995 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32996 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32998 nanText : "{0} is not a valid number",
33000 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33005 initEvents : function()
33007 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33009 var allowed = "0123456789";
33011 if(this.allowDecimals){
33012 allowed += this.decimalSeparator;
33015 if(this.allowNegative){
33019 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33021 var keyPress = function(e){
33023 var k = e.getKey();
33025 var c = e.getCharCode();
33028 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33029 allowed.indexOf(String.fromCharCode(c)) === -1
33035 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33039 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33044 this.el.on("keypress", keyPress, this);
33047 validateValue : function(value)
33050 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33054 var num = this.parseValue(value);
33057 this.markInvalid(String.format(this.nanText, value));
33061 if(num < this.minValue){
33062 this.markInvalid(String.format(this.minText, this.minValue));
33066 if(num > this.maxValue){
33067 this.markInvalid(String.format(this.maxText, this.maxValue));
33074 getValue : function()
33076 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
33079 parseValue : function(value)
33081 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33082 return isNaN(value) ? '' : value;
33085 fixPrecision : function(value)
33087 var nan = isNaN(value);
33089 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33090 return nan ? '' : value;
33092 return parseFloat(value).toFixed(this.decimalPrecision);
33095 setValue : function(v)
33097 v = this.fixPrecision(v);
33098 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
33101 decimalPrecisionFcn : function(v)
33103 return Math.floor(v);
33106 beforeBlur : function()
33112 var v = this.parseValue(this.getRawValue());
33127 * @class Roo.bootstrap.DocumentSlider
33128 * @extends Roo.bootstrap.Component
33129 * Bootstrap DocumentSlider class
33132 * Create a new DocumentViewer
33133 * @param {Object} config The config object
33136 Roo.bootstrap.DocumentSlider = function(config){
33137 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33144 * Fire after initEvent
33145 * @param {Roo.bootstrap.DocumentSlider} this
33150 * Fire after update
33151 * @param {Roo.bootstrap.DocumentSlider} this
33157 * @param {Roo.bootstrap.DocumentSlider} this
33163 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33169 getAutoCreate : function()
33173 cls : 'roo-document-slider',
33177 cls : 'roo-document-slider-header',
33181 cls : 'roo-document-slider-header-title'
33187 cls : 'roo-document-slider-body',
33191 cls : 'roo-document-slider-prev',
33195 cls : 'fa fa-chevron-left'
33201 cls : 'roo-document-slider-thumb',
33205 cls : 'roo-document-slider-image'
33211 cls : 'roo-document-slider-next',
33215 cls : 'fa fa-chevron-right'
33227 initEvents : function()
33229 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33230 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33232 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33233 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33235 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33236 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33238 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33239 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33241 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33242 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33244 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33245 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33247 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33248 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33250 this.thumbEl.on('click', this.onClick, this);
33252 this.prevIndicator.on('click', this.prev, this);
33254 this.nextIndicator.on('click', this.next, this);
33258 initial : function()
33260 if(this.files.length){
33261 this.indicator = 1;
33265 this.fireEvent('initial', this);
33268 update : function()
33270 this.imageEl.attr('src', this.files[this.indicator - 1]);
33272 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33274 this.prevIndicator.show();
33276 if(this.indicator == 1){
33277 this.prevIndicator.hide();
33280 this.nextIndicator.show();
33282 if(this.indicator == this.files.length){
33283 this.nextIndicator.hide();
33286 this.thumbEl.scrollTo('top');
33288 this.fireEvent('update', this);
33291 onClick : function(e)
33293 e.preventDefault();
33295 this.fireEvent('click', this);
33300 e.preventDefault();
33302 this.indicator = Math.max(1, this.indicator - 1);
33309 e.preventDefault();
33311 this.indicator = Math.min(this.files.length, this.indicator + 1);
33325 * @class Roo.bootstrap.RadioSet
33326 * @extends Roo.bootstrap.Input
33327 * Bootstrap RadioSet class
33328 * @cfg {String} indicatorpos (left|right) default left
33329 * @cfg {Boolean} inline (true|false) inline the element (default true)
33330 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33332 * Create a new RadioSet
33333 * @param {Object} config The config object
33336 Roo.bootstrap.RadioSet = function(config){
33338 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33342 Roo.bootstrap.RadioSet.register(this);
33347 * Fires when the element is checked or unchecked.
33348 * @param {Roo.bootstrap.RadioSet} this This radio
33349 * @param {Roo.bootstrap.Radio} item The checked item
33356 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33364 indicatorpos : 'left',
33366 getAutoCreate : function()
33370 cls : 'roo-radio-set-label',
33374 html : this.fieldLabel
33379 if(this.indicatorpos == 'left'){
33382 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33383 tooltip : 'This field is required'
33388 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33389 tooltip : 'This field is required'
33395 cls : 'roo-radio-set-items'
33398 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33400 if (align === 'left' && this.fieldLabel.length) {
33403 cls : "roo-radio-set-right",
33409 if(this.labelWidth > 12){
33410 label.style = "width: " + this.labelWidth + 'px';
33413 if(this.labelWidth < 13 && this.labelmd == 0){
33414 this.labelmd = this.labelWidth;
33417 if(this.labellg > 0){
33418 label.cls += ' col-lg-' + this.labellg;
33419 items.cls += ' col-lg-' + (12 - this.labellg);
33422 if(this.labelmd > 0){
33423 label.cls += ' col-md-' + this.labelmd;
33424 items.cls += ' col-md-' + (12 - this.labelmd);
33427 if(this.labelsm > 0){
33428 label.cls += ' col-sm-' + this.labelsm;
33429 items.cls += ' col-sm-' + (12 - this.labelsm);
33432 if(this.labelxs > 0){
33433 label.cls += ' col-xs-' + this.labelxs;
33434 items.cls += ' col-xs-' + (12 - this.labelxs);
33440 cls : 'roo-radio-set',
33444 cls : 'roo-radio-set-input',
33447 value : this.value ? this.value : ''
33454 if(this.weight.length){
33455 cfg.cls += ' roo-radio-' + this.weight;
33459 cfg.cls += ' roo-radio-set-inline';
33463 ['xs','sm','md','lg'].map(function(size){
33464 if (settings[size]) {
33465 cfg.cls += ' col-' + size + '-' + settings[size];
33473 initEvents : function()
33475 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33476 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33478 if(!this.fieldLabel.length){
33479 this.labelEl.hide();
33482 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33483 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33485 this.indicatorEl().addClass('invisible');
33487 this.originalValue = this.getValue();
33491 inputEl: function ()
33493 return this.el.select('.roo-radio-set-input', true).first();
33496 getChildContainer : function()
33498 return this.itemsEl;
33501 register : function(item)
33503 this.radioes.push(item);
33507 validate : function()
33511 Roo.each(this.radioes, function(i){
33520 if(this.allowBlank) {
33524 if(this.disabled || valid){
33529 this.markInvalid();
33534 markValid : function()
33536 if(this.labelEl.isVisible(true)){
33537 this.indicatorEl().removeClass('visible');
33538 this.indicatorEl().addClass('invisible');
33541 this.el.removeClass([this.invalidClass, this.validClass]);
33542 this.el.addClass(this.validClass);
33544 this.fireEvent('valid', this);
33547 markInvalid : function(msg)
33549 if(this.allowBlank || this.disabled){
33553 if(this.labelEl.isVisible(true)){
33554 this.indicatorEl().removeClass('invisible');
33555 this.indicatorEl().addClass('visible');
33558 this.el.removeClass([this.invalidClass, this.validClass]);
33559 this.el.addClass(this.invalidClass);
33561 this.fireEvent('invalid', this, msg);
33565 setValue : function(v, suppressEvent)
33567 if(this.value === v){
33574 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33577 Roo.each(this.radioes, function(i){
33580 i.el.removeClass('checked');
33582 if(i.value === v || i.value.toString() === v.toString()){
33584 i.el.addClass('checked');
33586 if(suppressEvent !== true){
33587 this.fireEvent('check', this, i);
33596 clearInvalid : function(){
33598 if(!this.el || this.preventMark){
33602 this.el.removeClass([this.invalidClass]);
33604 this.fireEvent('valid', this);
33609 Roo.apply(Roo.bootstrap.RadioSet, {
33613 register : function(set)
33615 this.groups[set.name] = set;
33618 get: function(name)
33620 if (typeof(this.groups[name]) == 'undefined') {
33624 return this.groups[name] ;
33630 * Ext JS Library 1.1.1
33631 * Copyright(c) 2006-2007, Ext JS, LLC.
33633 * Originally Released Under LGPL - original licence link has changed is not relivant.
33636 * <script type="text/javascript">
33641 * @class Roo.bootstrap.SplitBar
33642 * @extends Roo.util.Observable
33643 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33647 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33648 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33649 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33650 split.minSize = 100;
33651 split.maxSize = 600;
33652 split.animate = true;
33653 split.on('moved', splitterMoved);
33656 * Create a new SplitBar
33657 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33658 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33659 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33660 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33661 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33662 position of the SplitBar).
33664 Roo.bootstrap.SplitBar = function(cfg){
33669 // dragElement : elm
33670 // resizingElement: el,
33672 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33673 // placement : Roo.bootstrap.SplitBar.LEFT ,
33674 // existingProxy ???
33677 this.el = Roo.get(cfg.dragElement, true);
33678 this.el.dom.unselectable = "on";
33680 this.resizingEl = Roo.get(cfg.resizingElement, true);
33684 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33685 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33688 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33691 * The minimum size of the resizing element. (Defaults to 0)
33697 * The maximum size of the resizing element. (Defaults to 2000)
33700 this.maxSize = 2000;
33703 * Whether to animate the transition to the new size
33706 this.animate = false;
33709 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33712 this.useShim = false;
33717 if(!cfg.existingProxy){
33719 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33721 this.proxy = Roo.get(cfg.existingProxy).dom;
33724 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33727 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33730 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33733 this.dragSpecs = {};
33736 * @private The adapter to use to positon and resize elements
33738 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33739 this.adapter.init(this);
33741 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33743 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33744 this.el.addClass("roo-splitbar-h");
33747 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33748 this.el.addClass("roo-splitbar-v");
33754 * Fires when the splitter is moved (alias for {@link #event-moved})
33755 * @param {Roo.bootstrap.SplitBar} this
33756 * @param {Number} newSize the new width or height
33761 * Fires when the splitter is moved
33762 * @param {Roo.bootstrap.SplitBar} this
33763 * @param {Number} newSize the new width or height
33767 * @event beforeresize
33768 * Fires before the splitter is dragged
33769 * @param {Roo.bootstrap.SplitBar} this
33771 "beforeresize" : true,
33773 "beforeapply" : true
33776 Roo.util.Observable.call(this);
33779 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33780 onStartProxyDrag : function(x, y){
33781 this.fireEvent("beforeresize", this);
33783 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33785 o.enableDisplayMode("block");
33786 // all splitbars share the same overlay
33787 Roo.bootstrap.SplitBar.prototype.overlay = o;
33789 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33790 this.overlay.show();
33791 Roo.get(this.proxy).setDisplayed("block");
33792 var size = this.adapter.getElementSize(this);
33793 this.activeMinSize = this.getMinimumSize();;
33794 this.activeMaxSize = this.getMaximumSize();;
33795 var c1 = size - this.activeMinSize;
33796 var c2 = Math.max(this.activeMaxSize - size, 0);
33797 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33798 this.dd.resetConstraints();
33799 this.dd.setXConstraint(
33800 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33801 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33803 this.dd.setYConstraint(0, 0);
33805 this.dd.resetConstraints();
33806 this.dd.setXConstraint(0, 0);
33807 this.dd.setYConstraint(
33808 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33809 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33812 this.dragSpecs.startSize = size;
33813 this.dragSpecs.startPoint = [x, y];
33814 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33818 * @private Called after the drag operation by the DDProxy
33820 onEndProxyDrag : function(e){
33821 Roo.get(this.proxy).setDisplayed(false);
33822 var endPoint = Roo.lib.Event.getXY(e);
33824 this.overlay.hide();
33827 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33828 newSize = this.dragSpecs.startSize +
33829 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33830 endPoint[0] - this.dragSpecs.startPoint[0] :
33831 this.dragSpecs.startPoint[0] - endPoint[0]
33834 newSize = this.dragSpecs.startSize +
33835 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33836 endPoint[1] - this.dragSpecs.startPoint[1] :
33837 this.dragSpecs.startPoint[1] - endPoint[1]
33840 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33841 if(newSize != this.dragSpecs.startSize){
33842 if(this.fireEvent('beforeapply', this, newSize) !== false){
33843 this.adapter.setElementSize(this, newSize);
33844 this.fireEvent("moved", this, newSize);
33845 this.fireEvent("resize", this, newSize);
33851 * Get the adapter this SplitBar uses
33852 * @return The adapter object
33854 getAdapter : function(){
33855 return this.adapter;
33859 * Set the adapter this SplitBar uses
33860 * @param {Object} adapter A SplitBar adapter object
33862 setAdapter : function(adapter){
33863 this.adapter = adapter;
33864 this.adapter.init(this);
33868 * Gets the minimum size for the resizing element
33869 * @return {Number} The minimum size
33871 getMinimumSize : function(){
33872 return this.minSize;
33876 * Sets the minimum size for the resizing element
33877 * @param {Number} minSize The minimum size
33879 setMinimumSize : function(minSize){
33880 this.minSize = minSize;
33884 * Gets the maximum size for the resizing element
33885 * @return {Number} The maximum size
33887 getMaximumSize : function(){
33888 return this.maxSize;
33892 * Sets the maximum size for the resizing element
33893 * @param {Number} maxSize The maximum size
33895 setMaximumSize : function(maxSize){
33896 this.maxSize = maxSize;
33900 * Sets the initialize size for the resizing element
33901 * @param {Number} size The initial size
33903 setCurrentSize : function(size){
33904 var oldAnimate = this.animate;
33905 this.animate = false;
33906 this.adapter.setElementSize(this, size);
33907 this.animate = oldAnimate;
33911 * Destroy this splitbar.
33912 * @param {Boolean} removeEl True to remove the element
33914 destroy : function(removeEl){
33916 this.shim.remove();
33919 this.proxy.parentNode.removeChild(this.proxy);
33927 * @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.
33929 Roo.bootstrap.SplitBar.createProxy = function(dir){
33930 var proxy = new Roo.Element(document.createElement("div"));
33931 proxy.unselectable();
33932 var cls = 'roo-splitbar-proxy';
33933 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33934 document.body.appendChild(proxy.dom);
33939 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33940 * Default Adapter. It assumes the splitter and resizing element are not positioned
33941 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33943 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33946 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33947 // do nothing for now
33948 init : function(s){
33952 * Called before drag operations to get the current size of the resizing element.
33953 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33955 getElementSize : function(s){
33956 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33957 return s.resizingEl.getWidth();
33959 return s.resizingEl.getHeight();
33964 * Called after drag operations to set the size of the resizing element.
33965 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33966 * @param {Number} newSize The new size to set
33967 * @param {Function} onComplete A function to be invoked when resizing is complete
33969 setElementSize : function(s, newSize, onComplete){
33970 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33972 s.resizingEl.setWidth(newSize);
33974 onComplete(s, newSize);
33977 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33982 s.resizingEl.setHeight(newSize);
33984 onComplete(s, newSize);
33987 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33994 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33995 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33996 * Adapter that moves the splitter element to align with the resized sizing element.
33997 * Used with an absolute positioned SplitBar.
33998 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33999 * document.body, make sure you assign an id to the body element.
34001 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34002 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34003 this.container = Roo.get(container);
34006 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34007 init : function(s){
34008 this.basic.init(s);
34011 getElementSize : function(s){
34012 return this.basic.getElementSize(s);
34015 setElementSize : function(s, newSize, onComplete){
34016 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34019 moveSplitter : function(s){
34020 var yes = Roo.bootstrap.SplitBar;
34021 switch(s.placement){
34023 s.el.setX(s.resizingEl.getRight());
34026 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34029 s.el.setY(s.resizingEl.getBottom());
34032 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34039 * Orientation constant - Create a vertical SplitBar
34043 Roo.bootstrap.SplitBar.VERTICAL = 1;
34046 * Orientation constant - Create a horizontal SplitBar
34050 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34053 * Placement constant - The resizing element is to the left of the splitter element
34057 Roo.bootstrap.SplitBar.LEFT = 1;
34060 * Placement constant - The resizing element is to the right of the splitter element
34064 Roo.bootstrap.SplitBar.RIGHT = 2;
34067 * Placement constant - The resizing element is positioned above the splitter element
34071 Roo.bootstrap.SplitBar.TOP = 3;
34074 * Placement constant - The resizing element is positioned under splitter element
34078 Roo.bootstrap.SplitBar.BOTTOM = 4;
34079 Roo.namespace("Roo.bootstrap.layout");/*
34081 * Ext JS Library 1.1.1
34082 * Copyright(c) 2006-2007, Ext JS, LLC.
34084 * Originally Released Under LGPL - original licence link has changed is not relivant.
34087 * <script type="text/javascript">
34091 * @class Roo.bootstrap.layout.Manager
34092 * @extends Roo.bootstrap.Component
34093 * Base class for layout managers.
34095 Roo.bootstrap.layout.Manager = function(config)
34097 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34103 /** false to disable window resize monitoring @type Boolean */
34104 this.monitorWindowResize = true;
34109 * Fires when a layout is performed.
34110 * @param {Roo.LayoutManager} this
34114 * @event regionresized
34115 * Fires when the user resizes a region.
34116 * @param {Roo.LayoutRegion} region The resized region
34117 * @param {Number} newSize The new size (width for east/west, height for north/south)
34119 "regionresized" : true,
34121 * @event regioncollapsed
34122 * Fires when a region is collapsed.
34123 * @param {Roo.LayoutRegion} region The collapsed region
34125 "regioncollapsed" : true,
34127 * @event regionexpanded
34128 * Fires when a region is expanded.
34129 * @param {Roo.LayoutRegion} region The expanded region
34131 "regionexpanded" : true
34133 this.updating = false;
34136 this.el = Roo.get(config.el);
34142 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34147 monitorWindowResize : true,
34153 onRender : function(ct, position)
34156 this.el = Roo.get(ct);
34159 //this.fireEvent('render',this);
34163 initEvents: function()
34167 // ie scrollbar fix
34168 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34169 document.body.scroll = "no";
34170 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34171 this.el.position('relative');
34173 this.id = this.el.id;
34174 this.el.addClass("roo-layout-container");
34175 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34176 if(this.el.dom != document.body ) {
34177 this.el.on('resize', this.layout,this);
34178 this.el.on('show', this.layout,this);
34184 * Returns true if this layout is currently being updated
34185 * @return {Boolean}
34187 isUpdating : function(){
34188 return this.updating;
34192 * Suspend the LayoutManager from doing auto-layouts while
34193 * making multiple add or remove calls
34195 beginUpdate : function(){
34196 this.updating = true;
34200 * Restore auto-layouts and optionally disable the manager from performing a layout
34201 * @param {Boolean} noLayout true to disable a layout update
34203 endUpdate : function(noLayout){
34204 this.updating = false;
34210 layout: function(){
34214 onRegionResized : function(region, newSize){
34215 this.fireEvent("regionresized", region, newSize);
34219 onRegionCollapsed : function(region){
34220 this.fireEvent("regioncollapsed", region);
34223 onRegionExpanded : function(region){
34224 this.fireEvent("regionexpanded", region);
34228 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34229 * performs box-model adjustments.
34230 * @return {Object} The size as an object {width: (the width), height: (the height)}
34232 getViewSize : function()
34235 if(this.el.dom != document.body){
34236 size = this.el.getSize();
34238 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34240 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34241 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34246 * Returns the Element this layout is bound to.
34247 * @return {Roo.Element}
34249 getEl : function(){
34254 * Returns the specified region.
34255 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34256 * @return {Roo.LayoutRegion}
34258 getRegion : function(target){
34259 return this.regions[target.toLowerCase()];
34262 onWindowResize : function(){
34263 if(this.monitorWindowResize){
34270 * Ext JS Library 1.1.1
34271 * Copyright(c) 2006-2007, Ext JS, LLC.
34273 * Originally Released Under LGPL - original licence link has changed is not relivant.
34276 * <script type="text/javascript">
34279 * @class Roo.bootstrap.layout.Border
34280 * @extends Roo.bootstrap.layout.Manager
34281 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34282 * please see: examples/bootstrap/nested.html<br><br>
34284 <b>The container the layout is rendered into can be either the body element or any other element.
34285 If it is not the body element, the container needs to either be an absolute positioned element,
34286 or you will need to add "position:relative" to the css of the container. You will also need to specify
34287 the container size if it is not the body element.</b>
34290 * Create a new Border
34291 * @param {Object} config Configuration options
34293 Roo.bootstrap.layout.Border = function(config){
34294 config = config || {};
34295 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34299 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34300 if(config[region]){
34301 config[region].region = region;
34302 this.addRegion(config[region]);
34308 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34310 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34312 * Creates and adds a new region if it doesn't already exist.
34313 * @param {String} target The target region key (north, south, east, west or center).
34314 * @param {Object} config The regions config object
34315 * @return {BorderLayoutRegion} The new region
34317 addRegion : function(config)
34319 if(!this.regions[config.region]){
34320 var r = this.factory(config);
34321 this.bindRegion(r);
34323 return this.regions[config.region];
34327 bindRegion : function(r){
34328 this.regions[r.config.region] = r;
34330 r.on("visibilitychange", this.layout, this);
34331 r.on("paneladded", this.layout, this);
34332 r.on("panelremoved", this.layout, this);
34333 r.on("invalidated", this.layout, this);
34334 r.on("resized", this.onRegionResized, this);
34335 r.on("collapsed", this.onRegionCollapsed, this);
34336 r.on("expanded", this.onRegionExpanded, this);
34340 * Performs a layout update.
34342 layout : function()
34344 if(this.updating) {
34348 // render all the rebions if they have not been done alreayd?
34349 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34350 if(this.regions[region] && !this.regions[region].bodyEl){
34351 this.regions[region].onRender(this.el)
34355 var size = this.getViewSize();
34356 var w = size.width;
34357 var h = size.height;
34362 //var x = 0, y = 0;
34364 var rs = this.regions;
34365 var north = rs["north"];
34366 var south = rs["south"];
34367 var west = rs["west"];
34368 var east = rs["east"];
34369 var center = rs["center"];
34370 //if(this.hideOnLayout){ // not supported anymore
34371 //c.el.setStyle("display", "none");
34373 if(north && north.isVisible()){
34374 var b = north.getBox();
34375 var m = north.getMargins();
34376 b.width = w - (m.left+m.right);
34379 centerY = b.height + b.y + m.bottom;
34380 centerH -= centerY;
34381 north.updateBox(this.safeBox(b));
34383 if(south && south.isVisible()){
34384 var b = south.getBox();
34385 var m = south.getMargins();
34386 b.width = w - (m.left+m.right);
34388 var totalHeight = (b.height + m.top + m.bottom);
34389 b.y = h - totalHeight + m.top;
34390 centerH -= totalHeight;
34391 south.updateBox(this.safeBox(b));
34393 if(west && west.isVisible()){
34394 var b = west.getBox();
34395 var m = west.getMargins();
34396 b.height = centerH - (m.top+m.bottom);
34398 b.y = centerY + m.top;
34399 var totalWidth = (b.width + m.left + m.right);
34400 centerX += totalWidth;
34401 centerW -= totalWidth;
34402 west.updateBox(this.safeBox(b));
34404 if(east && east.isVisible()){
34405 var b = east.getBox();
34406 var m = east.getMargins();
34407 b.height = centerH - (m.top+m.bottom);
34408 var totalWidth = (b.width + m.left + m.right);
34409 b.x = w - totalWidth + m.left;
34410 b.y = centerY + m.top;
34411 centerW -= totalWidth;
34412 east.updateBox(this.safeBox(b));
34415 var m = center.getMargins();
34417 x: centerX + m.left,
34418 y: centerY + m.top,
34419 width: centerW - (m.left+m.right),
34420 height: centerH - (m.top+m.bottom)
34422 //if(this.hideOnLayout){
34423 //center.el.setStyle("display", "block");
34425 center.updateBox(this.safeBox(centerBox));
34428 this.fireEvent("layout", this);
34432 safeBox : function(box){
34433 box.width = Math.max(0, box.width);
34434 box.height = Math.max(0, box.height);
34439 * Adds a ContentPanel (or subclass) to this layout.
34440 * @param {String} target The target region key (north, south, east, west or center).
34441 * @param {Roo.ContentPanel} panel The panel to add
34442 * @return {Roo.ContentPanel} The added panel
34444 add : function(target, panel){
34446 target = target.toLowerCase();
34447 return this.regions[target].add(panel);
34451 * Remove a ContentPanel (or subclass) to this layout.
34452 * @param {String} target The target region key (north, south, east, west or center).
34453 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34454 * @return {Roo.ContentPanel} The removed panel
34456 remove : function(target, panel){
34457 target = target.toLowerCase();
34458 return this.regions[target].remove(panel);
34462 * Searches all regions for a panel with the specified id
34463 * @param {String} panelId
34464 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34466 findPanel : function(panelId){
34467 var rs = this.regions;
34468 for(var target in rs){
34469 if(typeof rs[target] != "function"){
34470 var p = rs[target].getPanel(panelId);
34480 * Searches all regions for a panel with the specified id and activates (shows) it.
34481 * @param {String/ContentPanel} panelId The panels id or the panel itself
34482 * @return {Roo.ContentPanel} The shown panel or null
34484 showPanel : function(panelId) {
34485 var rs = this.regions;
34486 for(var target in rs){
34487 var r = rs[target];
34488 if(typeof r != "function"){
34489 if(r.hasPanel(panelId)){
34490 return r.showPanel(panelId);
34498 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34499 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34502 restoreState : function(provider){
34504 provider = Roo.state.Manager;
34506 var sm = new Roo.LayoutStateManager();
34507 sm.init(this, provider);
34513 * Adds a xtype elements to the layout.
34517 xtype : 'ContentPanel',
34524 xtype : 'NestedLayoutPanel',
34530 items : [ ... list of content panels or nested layout panels.. ]
34534 * @param {Object} cfg Xtype definition of item to add.
34536 addxtype : function(cfg)
34538 // basically accepts a pannel...
34539 // can accept a layout region..!?!?
34540 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34543 // theory? children can only be panels??
34545 //if (!cfg.xtype.match(/Panel$/)) {
34550 if (typeof(cfg.region) == 'undefined') {
34551 Roo.log("Failed to add Panel, region was not set");
34555 var region = cfg.region;
34561 xitems = cfg.items;
34568 case 'Content': // ContentPanel (el, cfg)
34569 case 'Scroll': // ContentPanel (el, cfg)
34571 cfg.autoCreate = true;
34572 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34574 // var el = this.el.createChild();
34575 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34578 this.add(region, ret);
34582 case 'TreePanel': // our new panel!
34583 cfg.el = this.el.createChild();
34584 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34585 this.add(region, ret);
34590 // create a new Layout (which is a Border Layout...
34592 var clayout = cfg.layout;
34593 clayout.el = this.el.createChild();
34594 clayout.items = clayout.items || [];
34598 // replace this exitems with the clayout ones..
34599 xitems = clayout.items;
34601 // force background off if it's in center...
34602 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34603 cfg.background = false;
34605 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34608 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34609 //console.log('adding nested layout panel ' + cfg.toSource());
34610 this.add(region, ret);
34611 nb = {}; /// find first...
34616 // needs grid and region
34618 //var el = this.getRegion(region).el.createChild();
34620 *var el = this.el.createChild();
34621 // create the grid first...
34622 cfg.grid.container = el;
34623 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34626 if (region == 'center' && this.active ) {
34627 cfg.background = false;
34630 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34632 this.add(region, ret);
34634 if (cfg.background) {
34635 // render grid on panel activation (if panel background)
34636 ret.on('activate', function(gp) {
34637 if (!gp.grid.rendered) {
34638 // gp.grid.render(el);
34642 // cfg.grid.render(el);
34648 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34649 // it was the old xcomponent building that caused this before.
34650 // espeically if border is the top element in the tree.
34660 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34662 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34663 this.add(region, ret);
34667 throw "Can not add '" + cfg.xtype + "' to Border";
34673 this.beginUpdate();
34677 Roo.each(xitems, function(i) {
34678 region = nb && i.region ? i.region : false;
34680 var add = ret.addxtype(i);
34683 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34684 if (!i.background) {
34685 abn[region] = nb[region] ;
34692 // make the last non-background panel active..
34693 //if (nb) { Roo.log(abn); }
34696 for(var r in abn) {
34697 region = this.getRegion(r);
34699 // tried using nb[r], but it does not work..
34701 region.showPanel(abn[r]);
34712 factory : function(cfg)
34715 var validRegions = Roo.bootstrap.layout.Border.regions;
34717 var target = cfg.region;
34720 var r = Roo.bootstrap.layout;
34724 return new r.North(cfg);
34726 return new r.South(cfg);
34728 return new r.East(cfg);
34730 return new r.West(cfg);
34732 return new r.Center(cfg);
34734 throw 'Layout region "'+target+'" not supported.';
34741 * Ext JS Library 1.1.1
34742 * Copyright(c) 2006-2007, Ext JS, LLC.
34744 * Originally Released Under LGPL - original licence link has changed is not relivant.
34747 * <script type="text/javascript">
34751 * @class Roo.bootstrap.layout.Basic
34752 * @extends Roo.util.Observable
34753 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34754 * and does not have a titlebar, tabs or any other features. All it does is size and position
34755 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34756 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34757 * @cfg {string} region the region that it inhabits..
34758 * @cfg {bool} skipConfig skip config?
34762 Roo.bootstrap.layout.Basic = function(config){
34764 this.mgr = config.mgr;
34766 this.position = config.region;
34768 var skipConfig = config.skipConfig;
34772 * @scope Roo.BasicLayoutRegion
34776 * @event beforeremove
34777 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34778 * @param {Roo.LayoutRegion} this
34779 * @param {Roo.ContentPanel} panel The panel
34780 * @param {Object} e The cancel event object
34782 "beforeremove" : true,
34784 * @event invalidated
34785 * Fires when the layout for this region is changed.
34786 * @param {Roo.LayoutRegion} this
34788 "invalidated" : true,
34790 * @event visibilitychange
34791 * Fires when this region is shown or hidden
34792 * @param {Roo.LayoutRegion} this
34793 * @param {Boolean} visibility true or false
34795 "visibilitychange" : true,
34797 * @event paneladded
34798 * Fires when a panel is added.
34799 * @param {Roo.LayoutRegion} this
34800 * @param {Roo.ContentPanel} panel The panel
34802 "paneladded" : true,
34804 * @event panelremoved
34805 * Fires when a panel is removed.
34806 * @param {Roo.LayoutRegion} this
34807 * @param {Roo.ContentPanel} panel The panel
34809 "panelremoved" : true,
34811 * @event beforecollapse
34812 * Fires when this region before collapse.
34813 * @param {Roo.LayoutRegion} this
34815 "beforecollapse" : true,
34818 * Fires when this region is collapsed.
34819 * @param {Roo.LayoutRegion} this
34821 "collapsed" : true,
34824 * Fires when this region is expanded.
34825 * @param {Roo.LayoutRegion} this
34830 * Fires when this region is slid into view.
34831 * @param {Roo.LayoutRegion} this
34833 "slideshow" : true,
34836 * Fires when this region slides out of view.
34837 * @param {Roo.LayoutRegion} this
34839 "slidehide" : true,
34841 * @event panelactivated
34842 * Fires when a panel is activated.
34843 * @param {Roo.LayoutRegion} this
34844 * @param {Roo.ContentPanel} panel The activated panel
34846 "panelactivated" : true,
34849 * Fires when the user resizes this region.
34850 * @param {Roo.LayoutRegion} this
34851 * @param {Number} newSize The new size (width for east/west, height for north/south)
34855 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34856 this.panels = new Roo.util.MixedCollection();
34857 this.panels.getKey = this.getPanelId.createDelegate(this);
34859 this.activePanel = null;
34860 // ensure listeners are added...
34862 if (config.listeners || config.events) {
34863 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34864 listeners : config.listeners || {},
34865 events : config.events || {}
34869 if(skipConfig !== true){
34870 this.applyConfig(config);
34874 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34876 getPanelId : function(p){
34880 applyConfig : function(config){
34881 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34882 this.config = config;
34887 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34888 * the width, for horizontal (north, south) the height.
34889 * @param {Number} newSize The new width or height
34891 resizeTo : function(newSize){
34892 var el = this.el ? this.el :
34893 (this.activePanel ? this.activePanel.getEl() : null);
34895 switch(this.position){
34898 el.setWidth(newSize);
34899 this.fireEvent("resized", this, newSize);
34903 el.setHeight(newSize);
34904 this.fireEvent("resized", this, newSize);
34910 getBox : function(){
34911 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34914 getMargins : function(){
34915 return this.margins;
34918 updateBox : function(box){
34920 var el = this.activePanel.getEl();
34921 el.dom.style.left = box.x + "px";
34922 el.dom.style.top = box.y + "px";
34923 this.activePanel.setSize(box.width, box.height);
34927 * Returns the container element for this region.
34928 * @return {Roo.Element}
34930 getEl : function(){
34931 return this.activePanel;
34935 * Returns true if this region is currently visible.
34936 * @return {Boolean}
34938 isVisible : function(){
34939 return this.activePanel ? true : false;
34942 setActivePanel : function(panel){
34943 panel = this.getPanel(panel);
34944 if(this.activePanel && this.activePanel != panel){
34945 this.activePanel.setActiveState(false);
34946 this.activePanel.getEl().setLeftTop(-10000,-10000);
34948 this.activePanel = panel;
34949 panel.setActiveState(true);
34951 panel.setSize(this.box.width, this.box.height);
34953 this.fireEvent("panelactivated", this, panel);
34954 this.fireEvent("invalidated");
34958 * Show the specified panel.
34959 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34960 * @return {Roo.ContentPanel} The shown panel or null
34962 showPanel : function(panel){
34963 panel = this.getPanel(panel);
34965 this.setActivePanel(panel);
34971 * Get the active panel for this region.
34972 * @return {Roo.ContentPanel} The active panel or null
34974 getActivePanel : function(){
34975 return this.activePanel;
34979 * Add the passed ContentPanel(s)
34980 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34981 * @return {Roo.ContentPanel} The panel added (if only one was added)
34983 add : function(panel){
34984 if(arguments.length > 1){
34985 for(var i = 0, len = arguments.length; i < len; i++) {
34986 this.add(arguments[i]);
34990 if(this.hasPanel(panel)){
34991 this.showPanel(panel);
34994 var el = panel.getEl();
34995 if(el.dom.parentNode != this.mgr.el.dom){
34996 this.mgr.el.dom.appendChild(el.dom);
34998 if(panel.setRegion){
34999 panel.setRegion(this);
35001 this.panels.add(panel);
35002 el.setStyle("position", "absolute");
35003 if(!panel.background){
35004 this.setActivePanel(panel);
35005 if(this.config.initialSize && this.panels.getCount()==1){
35006 this.resizeTo(this.config.initialSize);
35009 this.fireEvent("paneladded", this, panel);
35014 * Returns true if the panel is in this region.
35015 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35016 * @return {Boolean}
35018 hasPanel : function(panel){
35019 if(typeof panel == "object"){ // must be panel obj
35020 panel = panel.getId();
35022 return this.getPanel(panel) ? true : false;
35026 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35027 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35028 * @param {Boolean} preservePanel Overrides the config preservePanel option
35029 * @return {Roo.ContentPanel} The panel that was removed
35031 remove : function(panel, preservePanel){
35032 panel = this.getPanel(panel);
35037 this.fireEvent("beforeremove", this, panel, e);
35038 if(e.cancel === true){
35041 var panelId = panel.getId();
35042 this.panels.removeKey(panelId);
35047 * Returns the panel specified or null if it's not in this region.
35048 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35049 * @return {Roo.ContentPanel}
35051 getPanel : function(id){
35052 if(typeof id == "object"){ // must be panel obj
35055 return this.panels.get(id);
35059 * Returns this regions position (north/south/east/west/center).
35062 getPosition: function(){
35063 return this.position;
35067 * Ext JS Library 1.1.1
35068 * Copyright(c) 2006-2007, Ext JS, LLC.
35070 * Originally Released Under LGPL - original licence link has changed is not relivant.
35073 * <script type="text/javascript">
35077 * @class Roo.bootstrap.layout.Region
35078 * @extends Roo.bootstrap.layout.Basic
35079 * This class represents a region in a layout manager.
35081 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35082 * @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})
35083 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35084 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35085 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35086 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35087 * @cfg {String} title The title for the region (overrides panel titles)
35088 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35089 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35090 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35091 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35092 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35093 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35094 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35095 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35096 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35097 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35099 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35100 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35101 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35102 * @cfg {Number} width For East/West panels
35103 * @cfg {Number} height For North/South panels
35104 * @cfg {Boolean} split To show the splitter
35105 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35107 * @cfg {string} cls Extra CSS classes to add to region
35109 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35110 * @cfg {string} region the region that it inhabits..
35113 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35114 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35116 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35117 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35118 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35120 Roo.bootstrap.layout.Region = function(config)
35122 this.applyConfig(config);
35124 var mgr = config.mgr;
35125 var pos = config.region;
35126 config.skipConfig = true;
35127 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35130 this.onRender(mgr.el);
35133 this.visible = true;
35134 this.collapsed = false;
35135 this.unrendered_panels = [];
35138 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35140 position: '', // set by wrapper (eg. north/south etc..)
35141 unrendered_panels : null, // unrendered panels.
35142 createBody : function(){
35143 /** This region's body element
35144 * @type Roo.Element */
35145 this.bodyEl = this.el.createChild({
35147 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35151 onRender: function(ctr, pos)
35153 var dh = Roo.DomHelper;
35154 /** This region's container element
35155 * @type Roo.Element */
35156 this.el = dh.append(ctr.dom, {
35158 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35160 /** This region's title element
35161 * @type Roo.Element */
35163 this.titleEl = dh.append(this.el.dom,
35166 unselectable: "on",
35167 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35169 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35170 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35173 this.titleEl.enableDisplayMode();
35174 /** This region's title text element
35175 * @type HTMLElement */
35176 this.titleTextEl = this.titleEl.dom.firstChild;
35177 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35179 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35180 this.closeBtn.enableDisplayMode();
35181 this.closeBtn.on("click", this.closeClicked, this);
35182 this.closeBtn.hide();
35184 this.createBody(this.config);
35185 if(this.config.hideWhenEmpty){
35187 this.on("paneladded", this.validateVisibility, this);
35188 this.on("panelremoved", this.validateVisibility, this);
35190 if(this.autoScroll){
35191 this.bodyEl.setStyle("overflow", "auto");
35193 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35195 //if(c.titlebar !== false){
35196 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35197 this.titleEl.hide();
35199 this.titleEl.show();
35200 if(this.config.title){
35201 this.titleTextEl.innerHTML = this.config.title;
35205 if(this.config.collapsed){
35206 this.collapse(true);
35208 if(this.config.hidden){
35212 if (this.unrendered_panels && this.unrendered_panels.length) {
35213 for (var i =0;i< this.unrendered_panels.length; i++) {
35214 this.add(this.unrendered_panels[i]);
35216 this.unrendered_panels = null;
35222 applyConfig : function(c)
35225 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35226 var dh = Roo.DomHelper;
35227 if(c.titlebar !== false){
35228 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35229 this.collapseBtn.on("click", this.collapse, this);
35230 this.collapseBtn.enableDisplayMode();
35232 if(c.showPin === true || this.showPin){
35233 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35234 this.stickBtn.enableDisplayMode();
35235 this.stickBtn.on("click", this.expand, this);
35236 this.stickBtn.hide();
35241 /** This region's collapsed element
35242 * @type Roo.Element */
35245 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35246 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35249 if(c.floatable !== false){
35250 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35251 this.collapsedEl.on("click", this.collapseClick, this);
35254 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35255 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35256 id: "message", unselectable: "on", style:{"float":"left"}});
35257 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35259 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35260 this.expandBtn.on("click", this.expand, this);
35264 if(this.collapseBtn){
35265 this.collapseBtn.setVisible(c.collapsible == true);
35268 this.cmargins = c.cmargins || this.cmargins ||
35269 (this.position == "west" || this.position == "east" ?
35270 {top: 0, left: 2, right:2, bottom: 0} :
35271 {top: 2, left: 0, right:0, bottom: 2});
35273 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35276 this.bottomTabs = c.tabPosition != "top";
35278 this.autoScroll = c.autoScroll || false;
35283 this.duration = c.duration || .30;
35284 this.slideDuration = c.slideDuration || .45;
35289 * Returns true if this region is currently visible.
35290 * @return {Boolean}
35292 isVisible : function(){
35293 return this.visible;
35297 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35298 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35300 //setCollapsedTitle : function(title){
35301 // title = title || " ";
35302 // if(this.collapsedTitleTextEl){
35303 // this.collapsedTitleTextEl.innerHTML = title;
35307 getBox : function(){
35309 // if(!this.collapsed){
35310 b = this.el.getBox(false, true);
35312 // b = this.collapsedEl.getBox(false, true);
35317 getMargins : function(){
35318 return this.margins;
35319 //return this.collapsed ? this.cmargins : this.margins;
35322 highlight : function(){
35323 this.el.addClass("x-layout-panel-dragover");
35326 unhighlight : function(){
35327 this.el.removeClass("x-layout-panel-dragover");
35330 updateBox : function(box)
35332 if (!this.bodyEl) {
35333 return; // not rendered yet..
35337 if(!this.collapsed){
35338 this.el.dom.style.left = box.x + "px";
35339 this.el.dom.style.top = box.y + "px";
35340 this.updateBody(box.width, box.height);
35342 this.collapsedEl.dom.style.left = box.x + "px";
35343 this.collapsedEl.dom.style.top = box.y + "px";
35344 this.collapsedEl.setSize(box.width, box.height);
35347 this.tabs.autoSizeTabs();
35351 updateBody : function(w, h)
35354 this.el.setWidth(w);
35355 w -= this.el.getBorderWidth("rl");
35356 if(this.config.adjustments){
35357 w += this.config.adjustments[0];
35360 if(h !== null && h > 0){
35361 this.el.setHeight(h);
35362 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35363 h -= this.el.getBorderWidth("tb");
35364 if(this.config.adjustments){
35365 h += this.config.adjustments[1];
35367 this.bodyEl.setHeight(h);
35369 h = this.tabs.syncHeight(h);
35372 if(this.panelSize){
35373 w = w !== null ? w : this.panelSize.width;
35374 h = h !== null ? h : this.panelSize.height;
35376 if(this.activePanel){
35377 var el = this.activePanel.getEl();
35378 w = w !== null ? w : el.getWidth();
35379 h = h !== null ? h : el.getHeight();
35380 this.panelSize = {width: w, height: h};
35381 this.activePanel.setSize(w, h);
35383 if(Roo.isIE && this.tabs){
35384 this.tabs.el.repaint();
35389 * Returns the container element for this region.
35390 * @return {Roo.Element}
35392 getEl : function(){
35397 * Hides this region.
35400 //if(!this.collapsed){
35401 this.el.dom.style.left = "-2000px";
35404 // this.collapsedEl.dom.style.left = "-2000px";
35405 // this.collapsedEl.hide();
35407 this.visible = false;
35408 this.fireEvent("visibilitychange", this, false);
35412 * Shows this region if it was previously hidden.
35415 //if(!this.collapsed){
35418 // this.collapsedEl.show();
35420 this.visible = true;
35421 this.fireEvent("visibilitychange", this, true);
35424 closeClicked : function(){
35425 if(this.activePanel){
35426 this.remove(this.activePanel);
35430 collapseClick : function(e){
35432 e.stopPropagation();
35435 e.stopPropagation();
35441 * Collapses this region.
35442 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35445 collapse : function(skipAnim, skipCheck = false){
35446 if(this.collapsed) {
35450 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35452 this.collapsed = true;
35454 this.split.el.hide();
35456 if(this.config.animate && skipAnim !== true){
35457 this.fireEvent("invalidated", this);
35458 this.animateCollapse();
35460 this.el.setLocation(-20000,-20000);
35462 this.collapsedEl.show();
35463 this.fireEvent("collapsed", this);
35464 this.fireEvent("invalidated", this);
35470 animateCollapse : function(){
35475 * Expands this region if it was previously collapsed.
35476 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35477 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35480 expand : function(e, skipAnim){
35482 e.stopPropagation();
35484 if(!this.collapsed || this.el.hasActiveFx()) {
35488 this.afterSlideIn();
35491 this.collapsed = false;
35492 if(this.config.animate && skipAnim !== true){
35493 this.animateExpand();
35497 this.split.el.show();
35499 this.collapsedEl.setLocation(-2000,-2000);
35500 this.collapsedEl.hide();
35501 this.fireEvent("invalidated", this);
35502 this.fireEvent("expanded", this);
35506 animateExpand : function(){
35510 initTabs : function()
35512 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35514 var ts = new Roo.bootstrap.panel.Tabs({
35515 el: this.bodyEl.dom,
35516 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35517 disableTooltips: this.config.disableTabTips,
35518 toolbar : this.config.toolbar
35521 if(this.config.hideTabs){
35522 ts.stripWrap.setDisplayed(false);
35525 ts.resizeTabs = this.config.resizeTabs === true;
35526 ts.minTabWidth = this.config.minTabWidth || 40;
35527 ts.maxTabWidth = this.config.maxTabWidth || 250;
35528 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35529 ts.monitorResize = false;
35530 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35531 ts.bodyEl.addClass('roo-layout-tabs-body');
35532 this.panels.each(this.initPanelAsTab, this);
35535 initPanelAsTab : function(panel){
35536 var ti = this.tabs.addTab(
35540 this.config.closeOnTab && panel.isClosable(),
35543 if(panel.tabTip !== undefined){
35544 ti.setTooltip(panel.tabTip);
35546 ti.on("activate", function(){
35547 this.setActivePanel(panel);
35550 if(this.config.closeOnTab){
35551 ti.on("beforeclose", function(t, e){
35553 this.remove(panel);
35557 panel.tabItem = ti;
35562 updatePanelTitle : function(panel, title)
35564 if(this.activePanel == panel){
35565 this.updateTitle(title);
35568 var ti = this.tabs.getTab(panel.getEl().id);
35570 if(panel.tabTip !== undefined){
35571 ti.setTooltip(panel.tabTip);
35576 updateTitle : function(title){
35577 if(this.titleTextEl && !this.config.title){
35578 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35582 setActivePanel : function(panel)
35584 panel = this.getPanel(panel);
35585 if(this.activePanel && this.activePanel != panel){
35586 if(this.activePanel.setActiveState(false) === false){
35590 this.activePanel = panel;
35591 panel.setActiveState(true);
35592 if(this.panelSize){
35593 panel.setSize(this.panelSize.width, this.panelSize.height);
35596 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35598 this.updateTitle(panel.getTitle());
35600 this.fireEvent("invalidated", this);
35602 this.fireEvent("panelactivated", this, panel);
35606 * Shows the specified panel.
35607 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35608 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35610 showPanel : function(panel)
35612 panel = this.getPanel(panel);
35615 var tab = this.tabs.getTab(panel.getEl().id);
35616 if(tab.isHidden()){
35617 this.tabs.unhideTab(tab.id);
35621 this.setActivePanel(panel);
35628 * Get the active panel for this region.
35629 * @return {Roo.ContentPanel} The active panel or null
35631 getActivePanel : function(){
35632 return this.activePanel;
35635 validateVisibility : function(){
35636 if(this.panels.getCount() < 1){
35637 this.updateTitle(" ");
35638 this.closeBtn.hide();
35641 if(!this.isVisible()){
35648 * Adds the passed ContentPanel(s) to this region.
35649 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35650 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35652 add : function(panel)
35654 if(arguments.length > 1){
35655 for(var i = 0, len = arguments.length; i < len; i++) {
35656 this.add(arguments[i]);
35661 // if we have not been rendered yet, then we can not really do much of this..
35662 if (!this.bodyEl) {
35663 this.unrendered_panels.push(panel);
35670 if(this.hasPanel(panel)){
35671 this.showPanel(panel);
35674 panel.setRegion(this);
35675 this.panels.add(panel);
35676 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35677 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35678 // and hide them... ???
35679 this.bodyEl.dom.appendChild(panel.getEl().dom);
35680 if(panel.background !== true){
35681 this.setActivePanel(panel);
35683 this.fireEvent("paneladded", this, panel);
35690 this.initPanelAsTab(panel);
35694 if(panel.background !== true){
35695 this.tabs.activate(panel.getEl().id);
35697 this.fireEvent("paneladded", this, panel);
35702 * Hides the tab for the specified panel.
35703 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35705 hidePanel : function(panel){
35706 if(this.tabs && (panel = this.getPanel(panel))){
35707 this.tabs.hideTab(panel.getEl().id);
35712 * Unhides the tab for a previously hidden panel.
35713 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35715 unhidePanel : function(panel){
35716 if(this.tabs && (panel = this.getPanel(panel))){
35717 this.tabs.unhideTab(panel.getEl().id);
35721 clearPanels : function(){
35722 while(this.panels.getCount() > 0){
35723 this.remove(this.panels.first());
35728 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35729 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35730 * @param {Boolean} preservePanel Overrides the config preservePanel option
35731 * @return {Roo.ContentPanel} The panel that was removed
35733 remove : function(panel, preservePanel)
35735 panel = this.getPanel(panel);
35740 this.fireEvent("beforeremove", this, panel, e);
35741 if(e.cancel === true){
35744 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35745 var panelId = panel.getId();
35746 this.panels.removeKey(panelId);
35748 document.body.appendChild(panel.getEl().dom);
35751 this.tabs.removeTab(panel.getEl().id);
35752 }else if (!preservePanel){
35753 this.bodyEl.dom.removeChild(panel.getEl().dom);
35755 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35756 var p = this.panels.first();
35757 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35758 tempEl.appendChild(p.getEl().dom);
35759 this.bodyEl.update("");
35760 this.bodyEl.dom.appendChild(p.getEl().dom);
35762 this.updateTitle(p.getTitle());
35764 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35765 this.setActivePanel(p);
35767 panel.setRegion(null);
35768 if(this.activePanel == panel){
35769 this.activePanel = null;
35771 if(this.config.autoDestroy !== false && preservePanel !== true){
35772 try{panel.destroy();}catch(e){}
35774 this.fireEvent("panelremoved", this, panel);
35779 * Returns the TabPanel component used by this region
35780 * @return {Roo.TabPanel}
35782 getTabs : function(){
35786 createTool : function(parentEl, className){
35787 var btn = Roo.DomHelper.append(parentEl, {
35789 cls: "x-layout-tools-button",
35792 cls: "roo-layout-tools-button-inner " + className,
35796 btn.addClassOnOver("roo-layout-tools-button-over");
35801 * Ext JS Library 1.1.1
35802 * Copyright(c) 2006-2007, Ext JS, LLC.
35804 * Originally Released Under LGPL - original licence link has changed is not relivant.
35807 * <script type="text/javascript">
35813 * @class Roo.SplitLayoutRegion
35814 * @extends Roo.LayoutRegion
35815 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35817 Roo.bootstrap.layout.Split = function(config){
35818 this.cursor = config.cursor;
35819 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35822 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35824 splitTip : "Drag to resize.",
35825 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35826 useSplitTips : false,
35828 applyConfig : function(config){
35829 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35832 onRender : function(ctr,pos) {
35834 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35835 if(!this.config.split){
35840 var splitEl = Roo.DomHelper.append(ctr.dom, {
35842 id: this.el.id + "-split",
35843 cls: "roo-layout-split roo-layout-split-"+this.position,
35846 /** The SplitBar for this region
35847 * @type Roo.SplitBar */
35848 // does not exist yet...
35849 Roo.log([this.position, this.orientation]);
35851 this.split = new Roo.bootstrap.SplitBar({
35852 dragElement : splitEl,
35853 resizingElement: this.el,
35854 orientation : this.orientation
35857 this.split.on("moved", this.onSplitMove, this);
35858 this.split.useShim = this.config.useShim === true;
35859 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35860 if(this.useSplitTips){
35861 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35863 //if(config.collapsible){
35864 // this.split.el.on("dblclick", this.collapse, this);
35867 if(typeof this.config.minSize != "undefined"){
35868 this.split.minSize = this.config.minSize;
35870 if(typeof this.config.maxSize != "undefined"){
35871 this.split.maxSize = this.config.maxSize;
35873 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35874 this.hideSplitter();
35879 getHMaxSize : function(){
35880 var cmax = this.config.maxSize || 10000;
35881 var center = this.mgr.getRegion("center");
35882 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35885 getVMaxSize : function(){
35886 var cmax = this.config.maxSize || 10000;
35887 var center = this.mgr.getRegion("center");
35888 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35891 onSplitMove : function(split, newSize){
35892 this.fireEvent("resized", this, newSize);
35896 * Returns the {@link Roo.SplitBar} for this region.
35897 * @return {Roo.SplitBar}
35899 getSplitBar : function(){
35904 this.hideSplitter();
35905 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35908 hideSplitter : function(){
35910 this.split.el.setLocation(-2000,-2000);
35911 this.split.el.hide();
35917 this.split.el.show();
35919 Roo.bootstrap.layout.Split.superclass.show.call(this);
35922 beforeSlide: function(){
35923 if(Roo.isGecko){// firefox overflow auto bug workaround
35924 this.bodyEl.clip();
35926 this.tabs.bodyEl.clip();
35928 if(this.activePanel){
35929 this.activePanel.getEl().clip();
35931 if(this.activePanel.beforeSlide){
35932 this.activePanel.beforeSlide();
35938 afterSlide : function(){
35939 if(Roo.isGecko){// firefox overflow auto bug workaround
35940 this.bodyEl.unclip();
35942 this.tabs.bodyEl.unclip();
35944 if(this.activePanel){
35945 this.activePanel.getEl().unclip();
35946 if(this.activePanel.afterSlide){
35947 this.activePanel.afterSlide();
35953 initAutoHide : function(){
35954 if(this.autoHide !== false){
35955 if(!this.autoHideHd){
35956 var st = new Roo.util.DelayedTask(this.slideIn, this);
35957 this.autoHideHd = {
35958 "mouseout": function(e){
35959 if(!e.within(this.el, true)){
35963 "mouseover" : function(e){
35969 this.el.on(this.autoHideHd);
35973 clearAutoHide : function(){
35974 if(this.autoHide !== false){
35975 this.el.un("mouseout", this.autoHideHd.mouseout);
35976 this.el.un("mouseover", this.autoHideHd.mouseover);
35980 clearMonitor : function(){
35981 Roo.get(document).un("click", this.slideInIf, this);
35984 // these names are backwards but not changed for compat
35985 slideOut : function(){
35986 if(this.isSlid || this.el.hasActiveFx()){
35989 this.isSlid = true;
35990 if(this.collapseBtn){
35991 this.collapseBtn.hide();
35993 this.closeBtnState = this.closeBtn.getStyle('display');
35994 this.closeBtn.hide();
35996 this.stickBtn.show();
35999 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36000 this.beforeSlide();
36001 this.el.setStyle("z-index", 10001);
36002 this.el.slideIn(this.getSlideAnchor(), {
36003 callback: function(){
36005 this.initAutoHide();
36006 Roo.get(document).on("click", this.slideInIf, this);
36007 this.fireEvent("slideshow", this);
36014 afterSlideIn : function(){
36015 this.clearAutoHide();
36016 this.isSlid = false;
36017 this.clearMonitor();
36018 this.el.setStyle("z-index", "");
36019 if(this.collapseBtn){
36020 this.collapseBtn.show();
36022 this.closeBtn.setStyle('display', this.closeBtnState);
36024 this.stickBtn.hide();
36026 this.fireEvent("slidehide", this);
36029 slideIn : function(cb){
36030 if(!this.isSlid || this.el.hasActiveFx()){
36034 this.isSlid = false;
36035 this.beforeSlide();
36036 this.el.slideOut(this.getSlideAnchor(), {
36037 callback: function(){
36038 this.el.setLeftTop(-10000, -10000);
36040 this.afterSlideIn();
36048 slideInIf : function(e){
36049 if(!e.within(this.el)){
36054 animateCollapse : function(){
36055 this.beforeSlide();
36056 this.el.setStyle("z-index", 20000);
36057 var anchor = this.getSlideAnchor();
36058 this.el.slideOut(anchor, {
36059 callback : function(){
36060 this.el.setStyle("z-index", "");
36061 this.collapsedEl.slideIn(anchor, {duration:.3});
36063 this.el.setLocation(-10000,-10000);
36065 this.fireEvent("collapsed", this);
36072 animateExpand : function(){
36073 this.beforeSlide();
36074 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36075 this.el.setStyle("z-index", 20000);
36076 this.collapsedEl.hide({
36079 this.el.slideIn(this.getSlideAnchor(), {
36080 callback : function(){
36081 this.el.setStyle("z-index", "");
36084 this.split.el.show();
36086 this.fireEvent("invalidated", this);
36087 this.fireEvent("expanded", this);
36115 getAnchor : function(){
36116 return this.anchors[this.position];
36119 getCollapseAnchor : function(){
36120 return this.canchors[this.position];
36123 getSlideAnchor : function(){
36124 return this.sanchors[this.position];
36127 getAlignAdj : function(){
36128 var cm = this.cmargins;
36129 switch(this.position){
36145 getExpandAdj : function(){
36146 var c = this.collapsedEl, cm = this.cmargins;
36147 switch(this.position){
36149 return [-(cm.right+c.getWidth()+cm.left), 0];
36152 return [cm.right+c.getWidth()+cm.left, 0];
36155 return [0, -(cm.top+cm.bottom+c.getHeight())];
36158 return [0, cm.top+cm.bottom+c.getHeight()];
36164 * Ext JS Library 1.1.1
36165 * Copyright(c) 2006-2007, Ext JS, LLC.
36167 * Originally Released Under LGPL - original licence link has changed is not relivant.
36170 * <script type="text/javascript">
36173 * These classes are private internal classes
36175 Roo.bootstrap.layout.Center = function(config){
36176 config.region = "center";
36177 Roo.bootstrap.layout.Region.call(this, config);
36178 this.visible = true;
36179 this.minWidth = config.minWidth || 20;
36180 this.minHeight = config.minHeight || 20;
36183 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36185 // center panel can't be hidden
36189 // center panel can't be hidden
36192 getMinWidth: function(){
36193 return this.minWidth;
36196 getMinHeight: function(){
36197 return this.minHeight;
36210 Roo.bootstrap.layout.North = function(config)
36212 config.region = 'north';
36213 config.cursor = 'n-resize';
36215 Roo.bootstrap.layout.Split.call(this, config);
36219 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36220 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36221 this.split.el.addClass("roo-layout-split-v");
36223 var size = config.initialSize || config.height;
36224 if(typeof size != "undefined"){
36225 this.el.setHeight(size);
36228 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36230 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36234 getBox : function(){
36235 if(this.collapsed){
36236 return this.collapsedEl.getBox();
36238 var box = this.el.getBox();
36240 box.height += this.split.el.getHeight();
36245 updateBox : function(box){
36246 if(this.split && !this.collapsed){
36247 box.height -= this.split.el.getHeight();
36248 this.split.el.setLeft(box.x);
36249 this.split.el.setTop(box.y+box.height);
36250 this.split.el.setWidth(box.width);
36252 if(this.collapsed){
36253 this.updateBody(box.width, null);
36255 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36263 Roo.bootstrap.layout.South = function(config){
36264 config.region = 'south';
36265 config.cursor = 's-resize';
36266 Roo.bootstrap.layout.Split.call(this, config);
36268 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36269 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36270 this.split.el.addClass("roo-layout-split-v");
36272 var size = config.initialSize || config.height;
36273 if(typeof size != "undefined"){
36274 this.el.setHeight(size);
36278 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36279 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36280 getBox : function(){
36281 if(this.collapsed){
36282 return this.collapsedEl.getBox();
36284 var box = this.el.getBox();
36286 var sh = this.split.el.getHeight();
36293 updateBox : function(box){
36294 if(this.split && !this.collapsed){
36295 var sh = this.split.el.getHeight();
36298 this.split.el.setLeft(box.x);
36299 this.split.el.setTop(box.y-sh);
36300 this.split.el.setWidth(box.width);
36302 if(this.collapsed){
36303 this.updateBody(box.width, null);
36305 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36309 Roo.bootstrap.layout.East = function(config){
36310 config.region = "east";
36311 config.cursor = "e-resize";
36312 Roo.bootstrap.layout.Split.call(this, config);
36314 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36315 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36316 this.split.el.addClass("roo-layout-split-h");
36318 var size = config.initialSize || config.width;
36319 if(typeof size != "undefined"){
36320 this.el.setWidth(size);
36323 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36324 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36325 getBox : function(){
36326 if(this.collapsed){
36327 return this.collapsedEl.getBox();
36329 var box = this.el.getBox();
36331 var sw = this.split.el.getWidth();
36338 updateBox : function(box){
36339 if(this.split && !this.collapsed){
36340 var sw = this.split.el.getWidth();
36342 this.split.el.setLeft(box.x);
36343 this.split.el.setTop(box.y);
36344 this.split.el.setHeight(box.height);
36347 if(this.collapsed){
36348 this.updateBody(null, box.height);
36350 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36354 Roo.bootstrap.layout.West = function(config){
36355 config.region = "west";
36356 config.cursor = "w-resize";
36358 Roo.bootstrap.layout.Split.call(this, config);
36360 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36361 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36362 this.split.el.addClass("roo-layout-split-h");
36366 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36367 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36369 onRender: function(ctr, pos)
36371 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36372 var size = this.config.initialSize || this.config.width;
36373 if(typeof size != "undefined"){
36374 this.el.setWidth(size);
36378 getBox : function(){
36379 if(this.collapsed){
36380 return this.collapsedEl.getBox();
36382 var box = this.el.getBox();
36384 box.width += this.split.el.getWidth();
36389 updateBox : function(box){
36390 if(this.split && !this.collapsed){
36391 var sw = this.split.el.getWidth();
36393 this.split.el.setLeft(box.x+box.width);
36394 this.split.el.setTop(box.y);
36395 this.split.el.setHeight(box.height);
36397 if(this.collapsed){
36398 this.updateBody(null, box.height);
36400 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36403 Roo.namespace("Roo.bootstrap.panel");/*
36405 * Ext JS Library 1.1.1
36406 * Copyright(c) 2006-2007, Ext JS, LLC.
36408 * Originally Released Under LGPL - original licence link has changed is not relivant.
36411 * <script type="text/javascript">
36414 * @class Roo.ContentPanel
36415 * @extends Roo.util.Observable
36416 * A basic ContentPanel element.
36417 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36418 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36419 * @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
36420 * @cfg {Boolean} closable True if the panel can be closed/removed
36421 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36422 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36423 * @cfg {Toolbar} toolbar A toolbar for this panel
36424 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36425 * @cfg {String} title The title for this panel
36426 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36427 * @cfg {String} url Calls {@link #setUrl} with this value
36428 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36429 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36430 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36431 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36432 * @cfg {Boolean} badges render the badges
36435 * Create a new ContentPanel.
36436 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36437 * @param {String/Object} config A string to set only the title or a config object
36438 * @param {String} content (optional) Set the HTML content for this panel
36439 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36441 Roo.bootstrap.panel.Content = function( config){
36443 this.tpl = config.tpl || false;
36445 var el = config.el;
36446 var content = config.content;
36448 if(config.autoCreate){ // xtype is available if this is called from factory
36451 this.el = Roo.get(el);
36452 if(!this.el && config && config.autoCreate){
36453 if(typeof config.autoCreate == "object"){
36454 if(!config.autoCreate.id){
36455 config.autoCreate.id = config.id||el;
36457 this.el = Roo.DomHelper.append(document.body,
36458 config.autoCreate, true);
36460 var elcfg = { tag: "div",
36461 cls: "roo-layout-inactive-content",
36465 elcfg.html = config.html;
36469 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36472 this.closable = false;
36473 this.loaded = false;
36474 this.active = false;
36477 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36479 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36481 this.wrapEl = this.el; //this.el.wrap();
36483 if (config.toolbar.items) {
36484 ti = config.toolbar.items ;
36485 delete config.toolbar.items ;
36489 this.toolbar.render(this.wrapEl, 'before');
36490 for(var i =0;i < ti.length;i++) {
36491 // Roo.log(['add child', items[i]]);
36492 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36494 this.toolbar.items = nitems;
36495 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36496 delete config.toolbar;
36500 // xtype created footer. - not sure if will work as we normally have to render first..
36501 if (this.footer && !this.footer.el && this.footer.xtype) {
36502 if (!this.wrapEl) {
36503 this.wrapEl = this.el.wrap();
36506 this.footer.container = this.wrapEl.createChild();
36508 this.footer = Roo.factory(this.footer, Roo);
36513 if(typeof config == "string"){
36514 this.title = config;
36516 Roo.apply(this, config);
36520 this.resizeEl = Roo.get(this.resizeEl, true);
36522 this.resizeEl = this.el;
36524 // handle view.xtype
36532 * Fires when this panel is activated.
36533 * @param {Roo.ContentPanel} this
36537 * @event deactivate
36538 * Fires when this panel is activated.
36539 * @param {Roo.ContentPanel} this
36541 "deactivate" : true,
36545 * Fires when this panel is resized if fitToFrame is true.
36546 * @param {Roo.ContentPanel} this
36547 * @param {Number} width The width after any component adjustments
36548 * @param {Number} height The height after any component adjustments
36554 * Fires when this tab is created
36555 * @param {Roo.ContentPanel} this
36566 if(this.autoScroll){
36567 this.resizeEl.setStyle("overflow", "auto");
36569 // fix randome scrolling
36570 //this.el.on('scroll', function() {
36571 // Roo.log('fix random scolling');
36572 // this.scrollTo('top',0);
36575 content = content || this.content;
36577 this.setContent(content);
36579 if(config && config.url){
36580 this.setUrl(this.url, this.params, this.loadOnce);
36585 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36587 if (this.view && typeof(this.view.xtype) != 'undefined') {
36588 this.view.el = this.el.appendChild(document.createElement("div"));
36589 this.view = Roo.factory(this.view);
36590 this.view.render && this.view.render(false, '');
36594 this.fireEvent('render', this);
36597 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36601 setRegion : function(region){
36602 this.region = region;
36603 this.setActiveClass(region && !this.background);
36607 setActiveClass: function(state)
36610 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36611 this.el.setStyle('position','relative');
36613 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36614 this.el.setStyle('position', 'absolute');
36619 * Returns the toolbar for this Panel if one was configured.
36620 * @return {Roo.Toolbar}
36622 getToolbar : function(){
36623 return this.toolbar;
36626 setActiveState : function(active)
36628 this.active = active;
36629 this.setActiveClass(active);
36631 if(this.fireEvent("deactivate", this) === false){
36636 this.fireEvent("activate", this);
36640 * Updates this panel's element
36641 * @param {String} content The new content
36642 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36644 setContent : function(content, loadScripts){
36645 this.el.update(content, loadScripts);
36648 ignoreResize : function(w, h){
36649 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36652 this.lastSize = {width: w, height: h};
36657 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36658 * @return {Roo.UpdateManager} The UpdateManager
36660 getUpdateManager : function(){
36661 return this.el.getUpdateManager();
36664 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36665 * @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:
36668 url: "your-url.php",
36669 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36670 callback: yourFunction,
36671 scope: yourObject, //(optional scope)
36674 text: "Loading...",
36679 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36680 * 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.
36681 * @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}
36682 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36683 * @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.
36684 * @return {Roo.ContentPanel} this
36687 var um = this.el.getUpdateManager();
36688 um.update.apply(um, arguments);
36694 * 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.
36695 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36696 * @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)
36697 * @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)
36698 * @return {Roo.UpdateManager} The UpdateManager
36700 setUrl : function(url, params, loadOnce){
36701 if(this.refreshDelegate){
36702 this.removeListener("activate", this.refreshDelegate);
36704 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36705 this.on("activate", this.refreshDelegate);
36706 return this.el.getUpdateManager();
36709 _handleRefresh : function(url, params, loadOnce){
36710 if(!loadOnce || !this.loaded){
36711 var updater = this.el.getUpdateManager();
36712 updater.update(url, params, this._setLoaded.createDelegate(this));
36716 _setLoaded : function(){
36717 this.loaded = true;
36721 * Returns this panel's id
36724 getId : function(){
36729 * Returns this panel's element - used by regiosn to add.
36730 * @return {Roo.Element}
36732 getEl : function(){
36733 return this.wrapEl || this.el;
36738 adjustForComponents : function(width, height)
36740 //Roo.log('adjustForComponents ');
36741 if(this.resizeEl != this.el){
36742 width -= this.el.getFrameWidth('lr');
36743 height -= this.el.getFrameWidth('tb');
36746 var te = this.toolbar.getEl();
36747 te.setWidth(width);
36748 height -= te.getHeight();
36751 var te = this.footer.getEl();
36752 te.setWidth(width);
36753 height -= te.getHeight();
36757 if(this.adjustments){
36758 width += this.adjustments[0];
36759 height += this.adjustments[1];
36761 return {"width": width, "height": height};
36764 setSize : function(width, height){
36765 if(this.fitToFrame && !this.ignoreResize(width, height)){
36766 if(this.fitContainer && this.resizeEl != this.el){
36767 this.el.setSize(width, height);
36769 var size = this.adjustForComponents(width, height);
36770 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36771 this.fireEvent('resize', this, size.width, size.height);
36776 * Returns this panel's title
36779 getTitle : function(){
36781 if (typeof(this.title) != 'object') {
36786 for (var k in this.title) {
36787 if (!this.title.hasOwnProperty(k)) {
36791 if (k.indexOf('-') >= 0) {
36792 var s = k.split('-');
36793 for (var i = 0; i<s.length; i++) {
36794 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36797 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36804 * Set this panel's title
36805 * @param {String} title
36807 setTitle : function(title){
36808 this.title = title;
36810 this.region.updatePanelTitle(this, title);
36815 * Returns true is this panel was configured to be closable
36816 * @return {Boolean}
36818 isClosable : function(){
36819 return this.closable;
36822 beforeSlide : function(){
36824 this.resizeEl.clip();
36827 afterSlide : function(){
36829 this.resizeEl.unclip();
36833 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36834 * Will fail silently if the {@link #setUrl} method has not been called.
36835 * This does not activate the panel, just updates its content.
36837 refresh : function(){
36838 if(this.refreshDelegate){
36839 this.loaded = false;
36840 this.refreshDelegate();
36845 * Destroys this panel
36847 destroy : function(){
36848 this.el.removeAllListeners();
36849 var tempEl = document.createElement("span");
36850 tempEl.appendChild(this.el.dom);
36851 tempEl.innerHTML = "";
36857 * form - if the content panel contains a form - this is a reference to it.
36858 * @type {Roo.form.Form}
36862 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36863 * This contains a reference to it.
36869 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36879 * @param {Object} cfg Xtype definition of item to add.
36883 getChildContainer: function () {
36884 return this.getEl();
36889 var ret = new Roo.factory(cfg);
36894 if (cfg.xtype.match(/^Form$/)) {
36897 //if (this.footer) {
36898 // el = this.footer.container.insertSibling(false, 'before');
36900 el = this.el.createChild();
36903 this.form = new Roo.form.Form(cfg);
36906 if ( this.form.allItems.length) {
36907 this.form.render(el.dom);
36911 // should only have one of theses..
36912 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36913 // views.. should not be just added - used named prop 'view''
36915 cfg.el = this.el.appendChild(document.createElement("div"));
36918 var ret = new Roo.factory(cfg);
36920 ret.render && ret.render(false, ''); // render blank..
36930 * @class Roo.bootstrap.panel.Grid
36931 * @extends Roo.bootstrap.panel.Content
36933 * Create a new GridPanel.
36934 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36935 * @param {Object} config A the config object
36941 Roo.bootstrap.panel.Grid = function(config)
36945 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36946 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36948 config.el = this.wrapper;
36949 //this.el = this.wrapper;
36951 if (config.container) {
36952 // ctor'ed from a Border/panel.grid
36955 this.wrapper.setStyle("overflow", "hidden");
36956 this.wrapper.addClass('roo-grid-container');
36961 if(config.toolbar){
36962 var tool_el = this.wrapper.createChild();
36963 this.toolbar = Roo.factory(config.toolbar);
36965 if (config.toolbar.items) {
36966 ti = config.toolbar.items ;
36967 delete config.toolbar.items ;
36971 this.toolbar.render(tool_el);
36972 for(var i =0;i < ti.length;i++) {
36973 // Roo.log(['add child', items[i]]);
36974 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36976 this.toolbar.items = nitems;
36978 delete config.toolbar;
36981 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36982 config.grid.scrollBody = true;;
36983 config.grid.monitorWindowResize = false; // turn off autosizing
36984 config.grid.autoHeight = false;
36985 config.grid.autoWidth = false;
36987 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36989 if (config.background) {
36990 // render grid on panel activation (if panel background)
36991 this.on('activate', function(gp) {
36992 if (!gp.grid.rendered) {
36993 gp.grid.render(this.wrapper);
36994 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36999 this.grid.render(this.wrapper);
37000 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37003 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37004 // ??? needed ??? config.el = this.wrapper;
37009 // xtype created footer. - not sure if will work as we normally have to render first..
37010 if (this.footer && !this.footer.el && this.footer.xtype) {
37012 var ctr = this.grid.getView().getFooterPanel(true);
37013 this.footer.dataSource = this.grid.dataSource;
37014 this.footer = Roo.factory(this.footer, Roo);
37015 this.footer.render(ctr);
37025 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37026 getId : function(){
37027 return this.grid.id;
37031 * Returns the grid for this panel
37032 * @return {Roo.bootstrap.Table}
37034 getGrid : function(){
37038 setSize : function(width, height){
37039 if(!this.ignoreResize(width, height)){
37040 var grid = this.grid;
37041 var size = this.adjustForComponents(width, height);
37042 var gridel = grid.getGridEl();
37043 gridel.setSize(size.width, size.height);
37045 var thd = grid.getGridEl().select('thead',true).first();
37046 var tbd = grid.getGridEl().select('tbody', true).first();
37048 tbd.setSize(width, height - thd.getHeight());
37057 beforeSlide : function(){
37058 this.grid.getView().scroller.clip();
37061 afterSlide : function(){
37062 this.grid.getView().scroller.unclip();
37065 destroy : function(){
37066 this.grid.destroy();
37068 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37073 * @class Roo.bootstrap.panel.Nest
37074 * @extends Roo.bootstrap.panel.Content
37076 * Create a new Panel, that can contain a layout.Border.
37079 * @param {Roo.BorderLayout} layout The layout for this panel
37080 * @param {String/Object} config A string to set only the title or a config object
37082 Roo.bootstrap.panel.Nest = function(config)
37084 // construct with only one argument..
37085 /* FIXME - implement nicer consturctors
37086 if (layout.layout) {
37088 layout = config.layout;
37089 delete config.layout;
37091 if (layout.xtype && !layout.getEl) {
37092 // then layout needs constructing..
37093 layout = Roo.factory(layout, Roo);
37097 config.el = config.layout.getEl();
37099 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37101 config.layout.monitorWindowResize = false; // turn off autosizing
37102 this.layout = config.layout;
37103 this.layout.getEl().addClass("roo-layout-nested-layout");
37110 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37112 setSize : function(width, height){
37113 if(!this.ignoreResize(width, height)){
37114 var size = this.adjustForComponents(width, height);
37115 var el = this.layout.getEl();
37116 if (size.height < 1) {
37117 el.setWidth(size.width);
37119 el.setSize(size.width, size.height);
37121 var touch = el.dom.offsetWidth;
37122 this.layout.layout();
37123 // ie requires a double layout on the first pass
37124 if(Roo.isIE && !this.initialized){
37125 this.initialized = true;
37126 this.layout.layout();
37131 // activate all subpanels if not currently active..
37133 setActiveState : function(active){
37134 this.active = active;
37135 this.setActiveClass(active);
37138 this.fireEvent("deactivate", this);
37142 this.fireEvent("activate", this);
37143 // not sure if this should happen before or after..
37144 if (!this.layout) {
37145 return; // should not happen..
37148 for (var r in this.layout.regions) {
37149 reg = this.layout.getRegion(r);
37150 if (reg.getActivePanel()) {
37151 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37152 reg.setActivePanel(reg.getActivePanel());
37155 if (!reg.panels.length) {
37158 reg.showPanel(reg.getPanel(0));
37167 * Returns the nested BorderLayout for this panel
37168 * @return {Roo.BorderLayout}
37170 getLayout : function(){
37171 return this.layout;
37175 * Adds a xtype elements to the layout of the nested panel
37179 xtype : 'ContentPanel',
37186 xtype : 'NestedLayoutPanel',
37192 items : [ ... list of content panels or nested layout panels.. ]
37196 * @param {Object} cfg Xtype definition of item to add.
37198 addxtype : function(cfg) {
37199 return this.layout.addxtype(cfg);
37204 * Ext JS Library 1.1.1
37205 * Copyright(c) 2006-2007, Ext JS, LLC.
37207 * Originally Released Under LGPL - original licence link has changed is not relivant.
37210 * <script type="text/javascript">
37213 * @class Roo.TabPanel
37214 * @extends Roo.util.Observable
37215 * A lightweight tab container.
37219 // basic tabs 1, built from existing content
37220 var tabs = new Roo.TabPanel("tabs1");
37221 tabs.addTab("script", "View Script");
37222 tabs.addTab("markup", "View Markup");
37223 tabs.activate("script");
37225 // more advanced tabs, built from javascript
37226 var jtabs = new Roo.TabPanel("jtabs");
37227 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37229 // set up the UpdateManager
37230 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37231 var updater = tab2.getUpdateManager();
37232 updater.setDefaultUrl("ajax1.htm");
37233 tab2.on('activate', updater.refresh, updater, true);
37235 // Use setUrl for Ajax loading
37236 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37237 tab3.setUrl("ajax2.htm", null, true);
37240 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37243 jtabs.activate("jtabs-1");
37246 * Create a new TabPanel.
37247 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37248 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37250 Roo.bootstrap.panel.Tabs = function(config){
37252 * The container element for this TabPanel.
37253 * @type Roo.Element
37255 this.el = Roo.get(config.el);
37258 if(typeof config == "boolean"){
37259 this.tabPosition = config ? "bottom" : "top";
37261 Roo.apply(this, config);
37265 if(this.tabPosition == "bottom"){
37266 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37267 this.el.addClass("roo-tabs-bottom");
37269 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37270 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37271 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37273 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37275 if(this.tabPosition != "bottom"){
37276 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37277 * @type Roo.Element
37279 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37280 this.el.addClass("roo-tabs-top");
37284 this.bodyEl.setStyle("position", "relative");
37286 this.active = null;
37287 this.activateDelegate = this.activate.createDelegate(this);
37292 * Fires when the active tab changes
37293 * @param {Roo.TabPanel} this
37294 * @param {Roo.TabPanelItem} activePanel The new active tab
37298 * @event beforetabchange
37299 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37300 * @param {Roo.TabPanel} this
37301 * @param {Object} e Set cancel to true on this object to cancel the tab change
37302 * @param {Roo.TabPanelItem} tab The tab being changed to
37304 "beforetabchange" : true
37307 Roo.EventManager.onWindowResize(this.onResize, this);
37308 this.cpad = this.el.getPadding("lr");
37309 this.hiddenCount = 0;
37312 // toolbar on the tabbar support...
37313 if (this.toolbar) {
37314 alert("no toolbar support yet");
37315 this.toolbar = false;
37317 var tcfg = this.toolbar;
37318 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37319 this.toolbar = new Roo.Toolbar(tcfg);
37320 if (Roo.isSafari) {
37321 var tbl = tcfg.container.child('table', true);
37322 tbl.setAttribute('width', '100%');
37330 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37333 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37335 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37337 tabPosition : "top",
37339 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37341 currentTabWidth : 0,
37343 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37347 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37351 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37353 preferredTabWidth : 175,
37355 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37357 resizeTabs : false,
37359 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37361 monitorResize : true,
37363 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37368 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37369 * @param {String} id The id of the div to use <b>or create</b>
37370 * @param {String} text The text for the tab
37371 * @param {String} content (optional) Content to put in the TabPanelItem body
37372 * @param {Boolean} closable (optional) True to create a close icon on the tab
37373 * @return {Roo.TabPanelItem} The created TabPanelItem
37375 addTab : function(id, text, content, closable, tpl)
37377 var item = new Roo.bootstrap.panel.TabItem({
37381 closable : closable,
37384 this.addTabItem(item);
37386 item.setContent(content);
37392 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37393 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37394 * @return {Roo.TabPanelItem}
37396 getTab : function(id){
37397 return this.items[id];
37401 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37402 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37404 hideTab : function(id){
37405 var t = this.items[id];
37408 this.hiddenCount++;
37409 this.autoSizeTabs();
37414 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37415 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37417 unhideTab : function(id){
37418 var t = this.items[id];
37420 t.setHidden(false);
37421 this.hiddenCount--;
37422 this.autoSizeTabs();
37427 * Adds an existing {@link Roo.TabPanelItem}.
37428 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37430 addTabItem : function(item){
37431 this.items[item.id] = item;
37432 this.items.push(item);
37433 // if(this.resizeTabs){
37434 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37435 // this.autoSizeTabs();
37437 // item.autoSize();
37442 * Removes a {@link Roo.TabPanelItem}.
37443 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37445 removeTab : function(id){
37446 var items = this.items;
37447 var tab = items[id];
37448 if(!tab) { return; }
37449 var index = items.indexOf(tab);
37450 if(this.active == tab && items.length > 1){
37451 var newTab = this.getNextAvailable(index);
37456 this.stripEl.dom.removeChild(tab.pnode.dom);
37457 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37458 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37460 items.splice(index, 1);
37461 delete this.items[tab.id];
37462 tab.fireEvent("close", tab);
37463 tab.purgeListeners();
37464 this.autoSizeTabs();
37467 getNextAvailable : function(start){
37468 var items = this.items;
37470 // look for a next tab that will slide over to
37471 // replace the one being removed
37472 while(index < items.length){
37473 var item = items[++index];
37474 if(item && !item.isHidden()){
37478 // if one isn't found select the previous tab (on the left)
37481 var item = items[--index];
37482 if(item && !item.isHidden()){
37490 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37491 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37493 disableTab : function(id){
37494 var tab = this.items[id];
37495 if(tab && this.active != tab){
37501 * Enables a {@link Roo.TabPanelItem} that is disabled.
37502 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37504 enableTab : function(id){
37505 var tab = this.items[id];
37510 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37511 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37512 * @return {Roo.TabPanelItem} The TabPanelItem.
37514 activate : function(id){
37515 var tab = this.items[id];
37519 if(tab == this.active || tab.disabled){
37523 this.fireEvent("beforetabchange", this, e, tab);
37524 if(e.cancel !== true && !tab.disabled){
37526 this.active.hide();
37528 this.active = this.items[id];
37529 this.active.show();
37530 this.fireEvent("tabchange", this, this.active);
37536 * Gets the active {@link Roo.TabPanelItem}.
37537 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37539 getActiveTab : function(){
37540 return this.active;
37544 * Updates the tab body element to fit the height of the container element
37545 * for overflow scrolling
37546 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37548 syncHeight : function(targetHeight){
37549 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37550 var bm = this.bodyEl.getMargins();
37551 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37552 this.bodyEl.setHeight(newHeight);
37556 onResize : function(){
37557 if(this.monitorResize){
37558 this.autoSizeTabs();
37563 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37565 beginUpdate : function(){
37566 this.updating = true;
37570 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37572 endUpdate : function(){
37573 this.updating = false;
37574 this.autoSizeTabs();
37578 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37580 autoSizeTabs : function(){
37581 var count = this.items.length;
37582 var vcount = count - this.hiddenCount;
37583 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37586 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37587 var availWidth = Math.floor(w / vcount);
37588 var b = this.stripBody;
37589 if(b.getWidth() > w){
37590 var tabs = this.items;
37591 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37592 if(availWidth < this.minTabWidth){
37593 /*if(!this.sleft){ // incomplete scrolling code
37594 this.createScrollButtons();
37597 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37600 if(this.currentTabWidth < this.preferredTabWidth){
37601 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37607 * Returns the number of tabs in this TabPanel.
37610 getCount : function(){
37611 return this.items.length;
37615 * Resizes all the tabs to the passed width
37616 * @param {Number} The new width
37618 setTabWidth : function(width){
37619 this.currentTabWidth = width;
37620 for(var i = 0, len = this.items.length; i < len; i++) {
37621 if(!this.items[i].isHidden()) {
37622 this.items[i].setWidth(width);
37628 * Destroys this TabPanel
37629 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37631 destroy : function(removeEl){
37632 Roo.EventManager.removeResizeListener(this.onResize, this);
37633 for(var i = 0, len = this.items.length; i < len; i++){
37634 this.items[i].purgeListeners();
37636 if(removeEl === true){
37637 this.el.update("");
37642 createStrip : function(container)
37644 var strip = document.createElement("nav");
37645 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37646 container.appendChild(strip);
37650 createStripList : function(strip)
37652 // div wrapper for retard IE
37653 // returns the "tr" element.
37654 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37655 //'<div class="x-tabs-strip-wrap">'+
37656 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37657 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37658 return strip.firstChild; //.firstChild.firstChild.firstChild;
37660 createBody : function(container)
37662 var body = document.createElement("div");
37663 Roo.id(body, "tab-body");
37664 //Roo.fly(body).addClass("x-tabs-body");
37665 Roo.fly(body).addClass("tab-content");
37666 container.appendChild(body);
37669 createItemBody :function(bodyEl, id){
37670 var body = Roo.getDom(id);
37672 body = document.createElement("div");
37675 //Roo.fly(body).addClass("x-tabs-item-body");
37676 Roo.fly(body).addClass("tab-pane");
37677 bodyEl.insertBefore(body, bodyEl.firstChild);
37681 createStripElements : function(stripEl, text, closable, tpl)
37683 var td = document.createElement("li"); // was td..
37686 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37689 stripEl.appendChild(td);
37691 td.className = "x-tabs-closable";
37692 if(!this.closeTpl){
37693 this.closeTpl = new Roo.Template(
37694 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37695 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37696 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37699 var el = this.closeTpl.overwrite(td, {"text": text});
37700 var close = el.getElementsByTagName("div")[0];
37701 var inner = el.getElementsByTagName("em")[0];
37702 return {"el": el, "close": close, "inner": inner};
37705 // not sure what this is..
37706 // if(!this.tabTpl){
37707 //this.tabTpl = new Roo.Template(
37708 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37709 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37711 // this.tabTpl = new Roo.Template(
37712 // '<a href="#">' +
37713 // '<span unselectable="on"' +
37714 // (this.disableTooltips ? '' : ' title="{text}"') +
37715 // ' >{text}</span></a>'
37721 var template = tpl || this.tabTpl || false;
37725 template = new Roo.Template(
37727 '<span unselectable="on"' +
37728 (this.disableTooltips ? '' : ' title="{text}"') +
37729 ' >{text}</span></a>'
37733 switch (typeof(template)) {
37737 template = new Roo.Template(template);
37743 var el = template.overwrite(td, {"text": text});
37745 var inner = el.getElementsByTagName("span")[0];
37747 return {"el": el, "inner": inner};
37755 * @class Roo.TabPanelItem
37756 * @extends Roo.util.Observable
37757 * Represents an individual item (tab plus body) in a TabPanel.
37758 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37759 * @param {String} id The id of this TabPanelItem
37760 * @param {String} text The text for the tab of this TabPanelItem
37761 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37763 Roo.bootstrap.panel.TabItem = function(config){
37765 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37766 * @type Roo.TabPanel
37768 this.tabPanel = config.panel;
37770 * The id for this TabPanelItem
37773 this.id = config.id;
37775 this.disabled = false;
37777 this.text = config.text;
37779 this.loaded = false;
37780 this.closable = config.closable;
37783 * The body element for this TabPanelItem.
37784 * @type Roo.Element
37786 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37787 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37788 this.bodyEl.setStyle("display", "block");
37789 this.bodyEl.setStyle("zoom", "1");
37790 //this.hideAction();
37792 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37794 this.el = Roo.get(els.el);
37795 this.inner = Roo.get(els.inner, true);
37796 this.textEl = Roo.get(this.el.dom.firstChild, true);
37797 this.pnode = Roo.get(els.el.parentNode, true);
37798 // this.el.on("mousedown", this.onTabMouseDown, this);
37799 this.el.on("click", this.onTabClick, this);
37801 if(config.closable){
37802 var c = Roo.get(els.close, true);
37803 c.dom.title = this.closeText;
37804 c.addClassOnOver("close-over");
37805 c.on("click", this.closeClick, this);
37811 * Fires when this tab becomes the active tab.
37812 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37813 * @param {Roo.TabPanelItem} this
37817 * @event beforeclose
37818 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37819 * @param {Roo.TabPanelItem} this
37820 * @param {Object} e Set cancel to true on this object to cancel the close.
37822 "beforeclose": true,
37825 * Fires when this tab is closed.
37826 * @param {Roo.TabPanelItem} this
37830 * @event deactivate
37831 * Fires when this tab is no longer the active tab.
37832 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37833 * @param {Roo.TabPanelItem} this
37835 "deactivate" : true
37837 this.hidden = false;
37839 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37842 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37844 purgeListeners : function(){
37845 Roo.util.Observable.prototype.purgeListeners.call(this);
37846 this.el.removeAllListeners();
37849 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37852 this.pnode.addClass("active");
37855 this.tabPanel.stripWrap.repaint();
37857 this.fireEvent("activate", this.tabPanel, this);
37861 * Returns true if this tab is the active tab.
37862 * @return {Boolean}
37864 isActive : function(){
37865 return this.tabPanel.getActiveTab() == this;
37869 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37872 this.pnode.removeClass("active");
37874 this.fireEvent("deactivate", this.tabPanel, this);
37877 hideAction : function(){
37878 this.bodyEl.hide();
37879 this.bodyEl.setStyle("position", "absolute");
37880 this.bodyEl.setLeft("-20000px");
37881 this.bodyEl.setTop("-20000px");
37884 showAction : function(){
37885 this.bodyEl.setStyle("position", "relative");
37886 this.bodyEl.setTop("");
37887 this.bodyEl.setLeft("");
37888 this.bodyEl.show();
37892 * Set the tooltip for the tab.
37893 * @param {String} tooltip The tab's tooltip
37895 setTooltip : function(text){
37896 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37897 this.textEl.dom.qtip = text;
37898 this.textEl.dom.removeAttribute('title');
37900 this.textEl.dom.title = text;
37904 onTabClick : function(e){
37905 e.preventDefault();
37906 this.tabPanel.activate(this.id);
37909 onTabMouseDown : function(e){
37910 e.preventDefault();
37911 this.tabPanel.activate(this.id);
37914 getWidth : function(){
37915 return this.inner.getWidth();
37918 setWidth : function(width){
37919 var iwidth = width - this.pnode.getPadding("lr");
37920 this.inner.setWidth(iwidth);
37921 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37922 this.pnode.setWidth(width);
37926 * Show or hide the tab
37927 * @param {Boolean} hidden True to hide or false to show.
37929 setHidden : function(hidden){
37930 this.hidden = hidden;
37931 this.pnode.setStyle("display", hidden ? "none" : "");
37935 * Returns true if this tab is "hidden"
37936 * @return {Boolean}
37938 isHidden : function(){
37939 return this.hidden;
37943 * Returns the text for this tab
37946 getText : function(){
37950 autoSize : function(){
37951 //this.el.beginMeasure();
37952 this.textEl.setWidth(1);
37954 * #2804 [new] Tabs in Roojs
37955 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37957 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37958 //this.el.endMeasure();
37962 * Sets the text for the tab (Note: this also sets the tooltip text)
37963 * @param {String} text The tab's text and tooltip
37965 setText : function(text){
37967 this.textEl.update(text);
37968 this.setTooltip(text);
37969 //if(!this.tabPanel.resizeTabs){
37970 // this.autoSize();
37974 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37976 activate : function(){
37977 this.tabPanel.activate(this.id);
37981 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37983 disable : function(){
37984 if(this.tabPanel.active != this){
37985 this.disabled = true;
37986 this.pnode.addClass("disabled");
37991 * Enables this TabPanelItem if it was previously disabled.
37993 enable : function(){
37994 this.disabled = false;
37995 this.pnode.removeClass("disabled");
37999 * Sets the content for this TabPanelItem.
38000 * @param {String} content The content
38001 * @param {Boolean} loadScripts true to look for and load scripts
38003 setContent : function(content, loadScripts){
38004 this.bodyEl.update(content, loadScripts);
38008 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38009 * @return {Roo.UpdateManager} The UpdateManager
38011 getUpdateManager : function(){
38012 return this.bodyEl.getUpdateManager();
38016 * Set a URL to be used to load the content for this TabPanelItem.
38017 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38018 * @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)
38019 * @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)
38020 * @return {Roo.UpdateManager} The UpdateManager
38022 setUrl : function(url, params, loadOnce){
38023 if(this.refreshDelegate){
38024 this.un('activate', this.refreshDelegate);
38026 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38027 this.on("activate", this.refreshDelegate);
38028 return this.bodyEl.getUpdateManager();
38032 _handleRefresh : function(url, params, loadOnce){
38033 if(!loadOnce || !this.loaded){
38034 var updater = this.bodyEl.getUpdateManager();
38035 updater.update(url, params, this._setLoaded.createDelegate(this));
38040 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38041 * Will fail silently if the setUrl method has not been called.
38042 * This does not activate the panel, just updates its content.
38044 refresh : function(){
38045 if(this.refreshDelegate){
38046 this.loaded = false;
38047 this.refreshDelegate();
38052 _setLoaded : function(){
38053 this.loaded = true;
38057 closeClick : function(e){
38060 this.fireEvent("beforeclose", this, o);
38061 if(o.cancel !== true){
38062 this.tabPanel.removeTab(this.id);
38066 * The text displayed in the tooltip for the close icon.
38069 closeText : "Close this tab"
38072 * This script refer to:
38073 * Title: International Telephone Input
38074 * Author: Jack O'Connor
38075 * Code version: v12.1.12
38076 * Availability: https://github.com/jackocnr/intl-tel-input.git
38079 Roo.bootstrap.PhoneInputData = function() {
38082 "Afghanistan (افغانستان)",
38087 "Albania (Shqipëri)",
38092 "Algeria (الجزائر)",
38117 "Antigua and Barbuda",
38127 "Armenia (Հայաստան)",
38143 "Austria (Österreich)",
38148 "Azerbaijan (Azərbaycan)",
38158 "Bahrain (البحرين)",
38163 "Bangladesh (বাংলাদেশ)",
38173 "Belarus (Беларусь)",
38178 "Belgium (België)",
38208 "Bosnia and Herzegovina (Босна и Херцеговина)",
38223 "British Indian Ocean Territory",
38228 "British Virgin Islands",
38238 "Bulgaria (България)",
38248 "Burundi (Uburundi)",
38253 "Cambodia (កម្ពុជា)",
38258 "Cameroon (Cameroun)",
38267 ["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"]
38270 "Cape Verde (Kabu Verdi)",
38275 "Caribbean Netherlands",
38286 "Central African Republic (République centrafricaine)",
38306 "Christmas Island",
38312 "Cocos (Keeling) Islands",
38323 "Comoros (جزر القمر)",
38328 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38333 "Congo (Republic) (Congo-Brazzaville)",
38353 "Croatia (Hrvatska)",
38374 "Czech Republic (Česká republika)",
38379 "Denmark (Danmark)",
38394 "Dominican Republic (República Dominicana)",
38398 ["809", "829", "849"]
38416 "Equatorial Guinea (Guinea Ecuatorial)",
38436 "Falkland Islands (Islas Malvinas)",
38441 "Faroe Islands (Føroyar)",
38462 "French Guiana (Guyane française)",
38467 "French Polynesia (Polynésie française)",
38482 "Georgia (საქართველო)",
38487 "Germany (Deutschland)",
38507 "Greenland (Kalaallit Nunaat)",
38544 "Guinea-Bissau (Guiné Bissau)",
38569 "Hungary (Magyarország)",
38574 "Iceland (Ísland)",
38594 "Iraq (العراق)",
38610 "Israel (ישראל)",
38637 "Jordan (الأردن)",
38642 "Kazakhstan (Казахстан)",
38663 "Kuwait (الكويت)",
38668 "Kyrgyzstan (Кыргызстан)",
38678 "Latvia (Latvija)",
38683 "Lebanon (لبنان)",
38698 "Libya (ليبيا)",
38708 "Lithuania (Lietuva)",
38723 "Macedonia (FYROM) (Македонија)",
38728 "Madagascar (Madagasikara)",
38758 "Marshall Islands",
38768 "Mauritania (موريتانيا)",
38773 "Mauritius (Moris)",
38794 "Moldova (Republica Moldova)",
38804 "Mongolia (Монгол)",
38809 "Montenegro (Crna Gora)",
38819 "Morocco (المغرب)",
38825 "Mozambique (Moçambique)",
38830 "Myanmar (Burma) (မြန်မာ)",
38835 "Namibia (Namibië)",
38850 "Netherlands (Nederland)",
38855 "New Caledonia (Nouvelle-Calédonie)",
38890 "North Korea (조선 민주주의 인민 공화국)",
38895 "Northern Mariana Islands",
38911 "Pakistan (پاکستان)",
38921 "Palestine (فلسطين)",
38931 "Papua New Guinea",
38973 "Réunion (La Réunion)",
38979 "Romania (România)",
38995 "Saint Barthélemy",
39006 "Saint Kitts and Nevis",
39016 "Saint Martin (Saint-Martin (partie française))",
39022 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39027 "Saint Vincent and the Grenadines",
39042 "São Tomé and Príncipe (São Tomé e Príncipe)",
39047 "Saudi Arabia (المملكة العربية السعودية)",
39052 "Senegal (Sénégal)",
39082 "Slovakia (Slovensko)",
39087 "Slovenia (Slovenija)",
39097 "Somalia (Soomaaliya)",
39107 "South Korea (대한민국)",
39112 "South Sudan (جنوب السودان)",
39122 "Sri Lanka (ශ්රී ලංකාව)",
39127 "Sudan (السودان)",
39137 "Svalbard and Jan Mayen",
39148 "Sweden (Sverige)",
39153 "Switzerland (Schweiz)",
39158 "Syria (سوريا)",
39203 "Trinidad and Tobago",
39208 "Tunisia (تونس)",
39213 "Turkey (Türkiye)",
39223 "Turks and Caicos Islands",
39233 "U.S. Virgin Islands",
39243 "Ukraine (Україна)",
39248 "United Arab Emirates (الإمارات العربية المتحدة)",
39270 "Uzbekistan (Oʻzbekiston)",
39280 "Vatican City (Città del Vaticano)",
39291 "Vietnam (Việt Nam)",
39296 "Wallis and Futuna (Wallis-et-Futuna)",
39301 "Western Sahara (الصحراء الغربية)",
39307 "Yemen (اليمن)",
39331 * This script refer to:
39332 * Title: International Telephone Input
39333 * Author: Jack O'Connor
39334 * Code version: v12.1.12
39335 * Availability: https://github.com/jackocnr/intl-tel-input.git
39339 * @class Roo.bootstrap.PhoneInput
39340 * @extends Roo.bootstrap.TriggerField
39341 * An input with International dial-code selection
39343 * @cfg {String} defaultDialCode default '+852'
39344 * @cfg {Array} preferedCountries default []
39347 * Create a new PhoneInput.
39348 * @param {Object} config Configuration options
39351 Roo.bootstrap.PhoneInput = function(config) {
39352 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39355 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39357 listWidth: undefined,
39359 selectedClass: 'active',
39361 invalidClass : "has-warning",
39363 validClass: 'has-success',
39365 allowed: '0123456789',
39368 * @cfg {String} defaultDialCode The default dial code when initializing the input
39370 defaultDialCode: '+852',
39373 * @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
39375 preferedCountries: false,
39377 getAutoCreate : function()
39379 var data = Roo.bootstrap.PhoneInputData();
39380 var align = this.labelAlign || this.parentLabelAlign();
39383 this.allCountries = [];
39384 this.dialCodeMapping = [];
39386 for (var i = 0; i < data.length; i++) {
39388 this.allCountries[i] = {
39392 priority: c[3] || 0,
39393 areaCodes: c[4] || null
39395 this.dialCodeMapping[c[2]] = {
39398 priority: c[3] || 0,
39399 areaCodes: c[4] || null
39411 cls : 'form-control tel-input',
39412 autocomplete: 'new-password'
39415 var hiddenInput = {
39418 cls: 'hidden-tel-input'
39422 hiddenInput.name = this.name;
39425 if (this.disabled) {
39426 input.disabled = true;
39429 var flag_container = {
39446 cls: this.hasFeedback ? 'has-feedback' : '',
39452 cls: 'dial-code-holder',
39459 cls: 'roo-select2-container input-group',
39466 if (this.fieldLabel.length) {
39469 tooltip: 'This field is required'
39475 cls: 'control-label',
39481 html: this.fieldLabel
39484 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39490 if(this.indicatorpos == 'right') {
39491 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39498 if(align == 'left') {
39506 if(this.labelWidth > 12){
39507 label.style = "width: " + this.labelWidth + 'px';
39509 if(this.labelWidth < 13 && this.labelmd == 0){
39510 this.labelmd = this.labelWidth;
39512 if(this.labellg > 0){
39513 label.cls += ' col-lg-' + this.labellg;
39514 input.cls += ' col-lg-' + (12 - this.labellg);
39516 if(this.labelmd > 0){
39517 label.cls += ' col-md-' + this.labelmd;
39518 container.cls += ' col-md-' + (12 - this.labelmd);
39520 if(this.labelsm > 0){
39521 label.cls += ' col-sm-' + this.labelsm;
39522 container.cls += ' col-sm-' + (12 - this.labelsm);
39524 if(this.labelxs > 0){
39525 label.cls += ' col-xs-' + this.labelxs;
39526 container.cls += ' col-xs-' + (12 - this.labelxs);
39536 var settings = this;
39538 ['xs','sm','md','lg'].map(function(size){
39539 if (settings[size]) {
39540 cfg.cls += ' col-' + size + '-' + settings[size];
39544 this.store = new Roo.data.Store({
39545 proxy : new Roo.data.MemoryProxy({}),
39546 reader : new Roo.data.JsonReader({
39557 'name' : 'dialCode',
39561 'name' : 'priority',
39565 'name' : 'areaCodes',
39572 if(!this.preferedCountries) {
39573 this.preferedCountries = [
39580 var p = this.preferedCountries.reverse();
39583 for (var i = 0; i < p.length; i++) {
39584 for (var j = 0; j < this.allCountries.length; j++) {
39585 if(this.allCountries[j].iso2 == p[i]) {
39586 var t = this.allCountries[j];
39587 this.allCountries.splice(j,1);
39588 this.allCountries.unshift(t);
39594 this.store.proxy.data = {
39596 data: this.allCountries
39602 initEvents : function()
39605 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39607 this.indicator = this.indicatorEl();
39608 this.flag = this.flagEl();
39609 this.dialCodeHolder = this.dialCodeHolderEl();
39611 this.trigger = this.el.select('div.flag-box',true).first();
39612 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39617 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39618 _this.list.setWidth(lw);
39621 this.list.on('mouseover', this.onViewOver, this);
39622 this.list.on('mousemove', this.onViewMove, this);
39623 this.inputEl().on("keyup", this.onKeyUp, this);
39625 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39627 this.view = new Roo.View(this.list, this.tpl, {
39628 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39631 this.view.on('click', this.onViewClick, this);
39632 this.setValue(this.defaultDialCode);
39635 onTriggerClick : function(e)
39637 Roo.log('trigger click');
39642 if(this.isExpanded()){
39644 this.hasFocus = false;
39646 this.store.load({});
39647 this.hasFocus = true;
39652 isExpanded : function()
39654 return this.list.isVisible();
39657 collapse : function()
39659 if(!this.isExpanded()){
39663 Roo.get(document).un('mousedown', this.collapseIf, this);
39664 Roo.get(document).un('mousewheel', this.collapseIf, this);
39665 this.fireEvent('collapse', this);
39669 expand : function()
39673 if(this.isExpanded() || !this.hasFocus){
39677 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39678 this.list.setWidth(lw);
39681 this.restrictHeight();
39683 Roo.get(document).on('mousedown', this.collapseIf, this);
39684 Roo.get(document).on('mousewheel', this.collapseIf, this);
39686 this.fireEvent('expand', this);
39689 restrictHeight : function()
39691 this.list.alignTo(this.inputEl(), this.listAlign);
39692 this.list.alignTo(this.inputEl(), this.listAlign);
39695 onViewOver : function(e, t)
39697 if(this.inKeyMode){
39700 var item = this.view.findItemFromChild(t);
39703 var index = this.view.indexOf(item);
39704 this.select(index, false);
39709 onViewClick : function(view, doFocus, el, e)
39711 var index = this.view.getSelectedIndexes()[0];
39713 var r = this.store.getAt(index);
39716 this.onSelect(r, index);
39718 if(doFocus !== false && !this.blockFocus){
39719 this.inputEl().focus();
39723 onViewMove : function(e, t)
39725 this.inKeyMode = false;
39728 select : function(index, scrollIntoView)
39730 this.selectedIndex = index;
39731 this.view.select(index);
39732 if(scrollIntoView !== false){
39733 var el = this.view.getNode(index);
39735 this.list.scrollChildIntoView(el, false);
39740 createList : function()
39742 this.list = Roo.get(document.body).createChild({
39744 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39745 style: 'display:none'
39747 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39750 collapseIf : function(e)
39752 var in_combo = e.within(this.el);
39753 var in_list = e.within(this.list);
39754 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39756 if (in_combo || in_list || is_list) {
39762 onSelect : function(record, index)
39764 if(this.fireEvent('beforeselect', this, record, index) !== false){
39766 this.setFlagClass(record.data.iso2);
39767 this.setDialCode(record.data.dialCode);
39768 this.hasFocus = false;
39770 this.fireEvent('select', this, record, index);
39774 flagEl : function()
39776 var flag = this.el.select('div.flag',true).first();
39783 dialCodeHolderEl : function()
39785 var d = this.el.select('input.dial-code-holder',true).first();
39792 setDialCode : function(v)
39794 this.dialCodeHolder.dom.value = '+'+v;
39797 setFlagClass : function(n)
39799 this.flag.dom.className = 'flag '+n;
39802 getValue : function()
39804 var v = this.inputEl().getValue();
39805 if(this.dialCodeHolder) {
39806 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39811 setValue : function(v)
39813 var d = this.getDialCode(v);
39815 //invalid dial code
39816 if(v.length == 0 || !d || d.length == 0) {
39818 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39819 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39825 this.setFlagClass(this.dialCodeMapping[d].iso2);
39826 this.setDialCode(d);
39827 this.inputEl().dom.value = v.replace('+'+d,'');
39828 this.hiddenEl().dom.value = this.getValue();
39833 getDialCode : function(v = '')
39835 if (v.length == 0) {
39836 return this.dialCodeHolder.dom.value;
39840 if (v.charAt(0) != "+") {
39843 var numericChars = "";
39844 for (var i = 1; i < v.length; i++) {
39845 var c = v.charAt(i);
39848 if (this.dialCodeMapping[numericChars]) {
39849 dialCode = v.substr(1, i);
39851 if (numericChars.length == 4) {
39861 this.setValue(this.defaultDialCode);
39865 hiddenEl : function()
39867 return this.el.select('input.hidden-tel-input',true).first();
39870 onKeyUp : function(e){
39872 var k = e.getKey();
39873 var c = e.getCharCode();
39876 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39877 this.allowed.indexOf(String.fromCharCode(c)) === -1
39882 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39885 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39889 this.setValue(this.getValue());
39894 * @class Roo.bootstrap.MoneyField
39895 * @extends Roo.bootstrap.ComboBox
39896 * Bootstrap MoneyField class
39899 * Create a new MoneyField.
39900 * @param {Object} config Configuration options
39903 Roo.bootstrap.MoneyField = function(config) {
39905 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39909 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39912 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39914 allowDecimals : true,
39916 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39918 decimalSeparator : ".",
39920 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39922 decimalPrecision : 2,
39924 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39926 allowNegative : true,
39928 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39930 minValue : Number.NEGATIVE_INFINITY,
39932 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39934 maxValue : Number.MAX_VALUE,
39936 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39938 minText : "The minimum value for this field is {0}",
39940 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39942 maxText : "The maximum value for this field is {0}",
39944 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39945 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39947 nanText : "{0} is not a valid number",
39949 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
39960 getAutoCreate : function()
39962 var align = this.labelAlign || this.parentLabelAlign();
39974 cls : 'form-control roo-money-amount-input',
39975 autocomplete: 'new-password'
39979 input.name = this.name;
39982 if (this.disabled) {
39983 input.disabled = true;
39986 var clg = 12 - this.inputlg;
39987 var cmd = 12 - this.inputmd;
39988 var csm = 12 - this.inputsm;
39989 var cxs = 12 - this.inputxs;
39993 cls : 'row roo-money-field',
39997 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40001 cls: 'roo-select2-container input-group',
40005 cls : 'form-control roo-money-currency-input',
40006 autocomplete: 'new-password',
40008 name : this.currencyName
40012 cls : 'input-group-addon',
40026 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40030 cls: this.hasFeedback ? 'has-feedback' : '',
40041 if (this.fieldLabel.length) {
40044 tooltip: 'This field is required'
40050 cls: 'control-label',
40056 html: this.fieldLabel
40059 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40065 if(this.indicatorpos == 'right') {
40066 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40073 if(align == 'left') {
40081 if(this.labelWidth > 12){
40082 label.style = "width: " + this.labelWidth + 'px';
40084 if(this.labelWidth < 13 && this.labelmd == 0){
40085 this.labelmd = this.labelWidth;
40087 if(this.labellg > 0){
40088 label.cls += ' col-lg-' + this.labellg;
40089 input.cls += ' col-lg-' + (12 - this.labellg);
40091 if(this.labelmd > 0){
40092 label.cls += ' col-md-' + this.labelmd;
40093 container.cls += ' col-md-' + (12 - this.labelmd);
40095 if(this.labelsm > 0){
40096 label.cls += ' col-sm-' + this.labelsm;
40097 container.cls += ' col-sm-' + (12 - this.labelsm);
40099 if(this.labelxs > 0){
40100 label.cls += ' col-xs-' + this.labelxs;
40101 container.cls += ' col-xs-' + (12 - this.labelxs);
40111 var settings = this;
40113 ['xs','sm','md','lg'].map(function(size){
40114 if (settings[size]) {
40115 cfg.cls += ' col-' + size + '-' + settings[size];
40123 initEvents : function()
40125 this.indicator = this.indicatorEl();
40127 this.initCurrencyEvent();
40129 this.initNumberEvent();
40133 initCurrencyEvent : function()
40136 throw "can not find store for combo";
40139 this.store = Roo.factory(this.store, Roo.data);
40140 this.store.parent = this;
40144 this.triggerEl = this.el.select('.input-group-addon', true).first();
40146 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40151 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40152 _this.list.setWidth(lw);
40155 this.list.on('mouseover', this.onViewOver, this);
40156 this.list.on('mousemove', this.onViewMove, this);
40157 this.list.on('scroll', this.onViewScroll, this);
40160 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40163 this.view = new Roo.View(this.list, this.tpl, {
40164 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40167 this.view.on('click', this.onViewClick, this);
40169 this.store.on('beforeload', this.onBeforeLoad, this);
40170 this.store.on('load', this.onLoad, this);
40171 this.store.on('loadexception', this.onLoadException, this);
40173 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40174 "up" : function(e){
40175 this.inKeyMode = true;
40179 "down" : function(e){
40180 if(!this.isExpanded()){
40181 this.onTriggerClick();
40183 this.inKeyMode = true;
40188 "enter" : function(e){
40191 if(this.fireEvent("specialkey", this, e)){
40192 this.onViewClick(false);
40198 "esc" : function(e){
40202 "tab" : function(e){
40205 if(this.fireEvent("specialkey", this, e)){
40206 this.onViewClick(false);
40214 doRelay : function(foo, bar, hname){
40215 if(hname == 'down' || this.scope.isExpanded()){
40216 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40224 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40228 initNumberEvent : function(e)
40230 this.inputEl().on("keydown" , this.fireKey, this);
40231 this.inputEl().on("focus", this.onFocus, this);
40232 this.inputEl().on("blur", this.onBlur, this);
40234 this.inputEl().relayEvent('keyup', this);
40236 if(this.indicator){
40237 this.indicator.addClass('invisible');
40240 this.originalValue = this.getValue();
40242 if(this.validationEvent == 'keyup'){
40243 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40244 this.inputEl().on('keyup', this.filterValidation, this);
40246 else if(this.validationEvent !== false){
40247 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40250 if(this.selectOnFocus){
40251 this.on("focus", this.preFocus, this);
40254 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40255 this.inputEl().on("keypress", this.filterKeys, this);
40257 this.inputEl().relayEvent('keypress', this);
40260 var allowed = "0123456789";
40262 if(this.allowDecimals){
40263 allowed += this.decimalSeparator;
40266 if(this.allowNegative){
40270 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40272 var keyPress = function(e){
40274 var k = e.getKey();
40276 var c = e.getCharCode();
40279 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40280 allowed.indexOf(String.fromCharCode(c)) === -1
40286 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40290 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40295 this.inputEl().on("keypress", keyPress, this);
40299 onTriggerClick : function(e)
40306 this.loadNext = false;
40308 if(this.isExpanded()){
40313 this.hasFocus = true;
40315 if(this.triggerAction == 'all') {
40316 this.doQuery(this.allQuery, true);
40320 this.doQuery(this.getRawValue());
40323 getCurrency : function()
40325 var v = this.currencyEl().getValue();
40330 restrictHeight : function()
40332 this.list.alignTo(this.currencyEl(), this.listAlign);
40333 this.list.alignTo(this.currencyEl(), this.listAlign);
40336 onViewClick : function(view, doFocus, el, e)
40338 var index = this.view.getSelectedIndexes()[0];
40340 var r = this.store.getAt(index);
40343 this.onSelect(r, index);
40347 onSelect : function(record, index){
40349 if(this.fireEvent('beforeselect', this, record, index) !== false){
40351 this.setFromCurrencyData(index > -1 ? record.data : false);
40355 this.fireEvent('select', this, record, index);
40359 setFromCurrencyData : function(o)
40363 this.lastCurrency = o;
40365 if (this.currencyField) {
40366 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40368 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40371 this.lastSelectionText = currency;
40373 this.setCurrency(currency);
40376 setFromData : function(o)
40380 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40382 this.setFromCurrencyData(c);
40387 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40389 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40392 this.setValue(value);
40396 setCurrency : function(v)
40398 this.currencyValue = v;
40401 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40406 setValue : function(v)
40408 v = this.fixPrecision(v);
40410 v = String(v).replace(".", this.decimalSeparator);
40415 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40420 getRawValue : function()
40422 var v = this.inputEl().getValue();
40427 getValue : function()
40429 return this.fixPrecision(this.parseValue(this.getRawValue()));
40432 parseValue : function(value)
40434 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40435 return isNaN(value) ? '' : value;
40438 fixPrecision : function(value)
40440 var nan = isNaN(value);
40442 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40443 return nan ? '' : value;
40446 return parseFloat(value).toFixed(this.decimalPrecision);
40449 decimalPrecisionFcn : function(v)
40451 return Math.floor(v);
40454 validateValue : function(value)
40456 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40460 var num = this.parseValue(value);
40463 this.markInvalid(String.format(this.nanText, value));
40467 if(num < this.minValue){
40468 this.markInvalid(String.format(this.minText, this.minValue));
40472 if(num > this.maxValue){
40473 this.markInvalid(String.format(this.maxText, this.maxValue));
40480 validate : function()
40482 if(this.disabled || this.allowBlank){
40487 var currency = this.getCurrency();
40489 if(this.validateValue(this.getRawValue()) && currency.length){
40494 this.markInvalid();
40498 getName: function()
40503 beforeBlur : function()
40509 var v = this.parseValue(this.getRawValue());
40516 onBlur : function()
40520 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40521 //this.el.removeClass(this.focusClass);
40524 this.hasFocus = false;
40526 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40530 var v = this.getValue();
40532 if(String(v) !== String(this.startValue)){
40533 this.fireEvent('change', this, v, this.startValue);
40536 this.fireEvent("blur", this);
40539 inputEl : function()
40541 return this.el.select('.roo-money-amount-input', true).first();
40544 currencyEl : function()
40546 return this.el.select('.roo-money-currency-input', true).first();