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);
3192 if (pp) { // weird bug on my firefox - for some reason this is not defined
3193 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3199 * Returns true if the message box is currently displayed
3200 * @return {Boolean} True if the message box is visible, else false
3202 isVisible : function(){
3203 return dlg && dlg.isVisible();
3207 * Hides the message box if it is displayed
3210 if(this.isVisible()){
3216 * Displays a new message box, or reinitializes an existing message box, based on the config options
3217 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3218 * The following config object properties are supported:
3220 Property Type Description
3221 ---------- --------------- ------------------------------------------------------------------------------------
3222 animEl String/Element An id or Element from which the message box should animate as it opens and
3223 closes (defaults to undefined)
3224 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3225 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3226 closable Boolean False to hide the top-right close button (defaults to true). Note that
3227 progress and wait dialogs will ignore this property and always hide the
3228 close button as they can only be closed programmatically.
3229 cls String A custom CSS class to apply to the message box element
3230 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3231 displayed (defaults to 75)
3232 fn Function A callback function to execute after closing the dialog. The arguments to the
3233 function will be btn (the name of the button that was clicked, if applicable,
3234 e.g. "ok"), and text (the value of the active text field, if applicable).
3235 Progress and wait dialogs will ignore this option since they do not respond to
3236 user actions and can only be closed programmatically, so any required function
3237 should be called by the same code after it closes the dialog.
3238 icon String A CSS class that provides a background image to be used as an icon for
3239 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3240 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3241 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3242 modal Boolean False to allow user interaction with the page while the message box is
3243 displayed (defaults to true)
3244 msg String A string that will replace the existing message box body text (defaults
3245 to the XHTML-compliant non-breaking space character ' ')
3246 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3247 progress Boolean True to display a progress bar (defaults to false)
3248 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3249 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3250 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3251 title String The title text
3252 value String The string value to set into the active textbox element if displayed
3253 wait Boolean True to display a progress bar (defaults to false)
3254 width Number The width of the dialog in pixels
3261 msg: 'Please enter your address:',
3263 buttons: Roo.MessageBox.OKCANCEL,
3266 animEl: 'addAddressBtn'
3269 * @param {Object} config Configuration options
3270 * @return {Roo.MessageBox} This message box
3272 show : function(options)
3275 // this causes nightmares if you show one dialog after another
3276 // especially on callbacks..
3278 if(this.isVisible()){
3281 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3282 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3283 Roo.log("New Dialog Message:" + options.msg )
3284 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3285 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3288 var d = this.getDialog();
3290 d.setTitle(opt.title || " ");
3291 d.closeEl.setDisplayed(opt.closable !== false);
3292 activeTextEl = textboxEl;
3293 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3298 textareaEl.setHeight(typeof opt.multiline == "number" ?
3299 opt.multiline : this.defaultTextHeight);
3300 activeTextEl = textareaEl;
3309 progressEl.setDisplayed(opt.progress === true);
3310 this.updateProgress(0);
3311 activeTextEl.dom.value = opt.value || "";
3313 dlg.setDefaultButton(activeTextEl);
3315 var bs = opt.buttons;
3319 }else if(bs && bs.yes){
3320 db = buttons["yes"];
3322 dlg.setDefaultButton(db);
3324 bwidth = updateButtons(opt.buttons);
3325 this.updateText(opt.msg);
3327 d.el.addClass(opt.cls);
3329 d.proxyDrag = opt.proxyDrag === true;
3330 d.modal = opt.modal !== false;
3331 d.mask = opt.modal !== false ? mask : false;
3333 // force it to the end of the z-index stack so it gets a cursor in FF
3334 document.body.appendChild(dlg.el.dom);
3335 d.animateTarget = null;
3336 d.show(options.animEl);
3342 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3343 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3344 * and closing the message box when the process is complete.
3345 * @param {String} title The title bar text
3346 * @param {String} msg The message box body text
3347 * @return {Roo.MessageBox} This message box
3349 progress : function(title, msg){
3356 minWidth: this.minProgressWidth,
3363 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3364 * If a callback function is passed it will be called after the user clicks the button, and the
3365 * id of the button that was clicked will be passed as the only parameter to the callback
3366 * (could also be the top-right close button).
3367 * @param {String} title The title bar text
3368 * @param {String} msg The message box body text
3369 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3370 * @param {Object} scope (optional) The scope of the callback function
3371 * @return {Roo.MessageBox} This message box
3373 alert : function(title, msg, fn, scope)
3388 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3389 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3390 * You are responsible for closing the message box when the process is complete.
3391 * @param {String} msg The message box body text
3392 * @param {String} title (optional) The title bar text
3393 * @return {Roo.MessageBox} This message box
3395 wait : function(msg, title){
3406 waitTimer = Roo.TaskMgr.start({
3408 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3416 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3417 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3418 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3419 * @param {String} title The title bar text
3420 * @param {String} msg The message box body text
3421 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3422 * @param {Object} scope (optional) The scope of the callback function
3423 * @return {Roo.MessageBox} This message box
3425 confirm : function(title, msg, fn, scope){
3429 buttons: this.YESNO,
3438 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3439 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3440 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3441 * (could also be the top-right close button) and the text that was entered will be passed as the two
3442 * parameters to the callback.
3443 * @param {String} title The title bar text
3444 * @param {String} msg The message box body text
3445 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3446 * @param {Object} scope (optional) The scope of the callback function
3447 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3448 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3449 * @return {Roo.MessageBox} This message box
3451 prompt : function(title, msg, fn, scope, multiline){
3455 buttons: this.OKCANCEL,
3460 multiline: multiline,
3467 * Button config that displays a single OK button
3472 * Button config that displays Yes and No buttons
3475 YESNO : {yes:true, no:true},
3477 * Button config that displays OK and Cancel buttons
3480 OKCANCEL : {ok:true, cancel:true},
3482 * Button config that displays Yes, No and Cancel buttons
3485 YESNOCANCEL : {yes:true, no:true, cancel:true},
3488 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3491 defaultTextHeight : 75,
3493 * The maximum width in pixels of the message box (defaults to 600)
3498 * The minimum width in pixels of the message box (defaults to 100)
3503 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3504 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3507 minProgressWidth : 250,
3509 * An object containing the default button text strings that can be overriden for localized language support.
3510 * Supported properties are: ok, cancel, yes and no.
3511 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3524 * Shorthand for {@link Roo.MessageBox}
3526 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3527 Roo.Msg = Roo.Msg || Roo.MessageBox;
3536 * @class Roo.bootstrap.Navbar
3537 * @extends Roo.bootstrap.Component
3538 * Bootstrap Navbar class
3541 * Create a new Navbar
3542 * @param {Object} config The config object
3546 Roo.bootstrap.Navbar = function(config){
3547 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3551 * @event beforetoggle
3552 * Fire before toggle the menu
3553 * @param {Roo.EventObject} e
3555 "beforetoggle" : true
3559 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3568 getAutoCreate : function(){
3571 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3575 initEvents :function ()
3577 //Roo.log(this.el.select('.navbar-toggle',true));
3578 this.el.select('.navbar-toggle',true).on('click', function() {
3579 if(this.fireEvent('beforetoggle', this) !== false){
3580 this.el.select('.navbar-collapse',true).toggleClass('in');
3590 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3592 var size = this.el.getSize();
3593 this.maskEl.setSize(size.width, size.height);
3594 this.maskEl.enableDisplayMode("block");
3603 getChildContainer : function()
3605 if (this.el.select('.collapse').getCount()) {
3606 return this.el.select('.collapse',true).first();
3639 * @class Roo.bootstrap.NavSimplebar
3640 * @extends Roo.bootstrap.Navbar
3641 * Bootstrap Sidebar class
3643 * @cfg {Boolean} inverse is inverted color
3645 * @cfg {String} type (nav | pills | tabs)
3646 * @cfg {Boolean} arrangement stacked | justified
3647 * @cfg {String} align (left | right) alignment
3649 * @cfg {Boolean} main (true|false) main nav bar? default false
3650 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3652 * @cfg {String} tag (header|footer|nav|div) default is nav
3658 * Create a new Sidebar
3659 * @param {Object} config The config object
3663 Roo.bootstrap.NavSimplebar = function(config){
3664 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3667 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3683 getAutoCreate : function(){
3687 tag : this.tag || 'div',
3700 this.type = this.type || 'nav';
3701 if (['tabs','pills'].indexOf(this.type)!==-1) {
3702 cfg.cn[0].cls += ' nav-' + this.type
3706 if (this.type!=='nav') {
3707 Roo.log('nav type must be nav/tabs/pills')
3709 cfg.cn[0].cls += ' navbar-nav'
3715 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3716 cfg.cn[0].cls += ' nav-' + this.arrangement;
3720 if (this.align === 'right') {
3721 cfg.cn[0].cls += ' navbar-right';
3725 cfg.cls += ' navbar-inverse';
3752 * @class Roo.bootstrap.NavHeaderbar
3753 * @extends Roo.bootstrap.NavSimplebar
3754 * Bootstrap Sidebar class
3756 * @cfg {String} brand what is brand
3757 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3758 * @cfg {String} brand_href href of the brand
3759 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3760 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3761 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3762 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3765 * Create a new Sidebar
3766 * @param {Object} config The config object
3770 Roo.bootstrap.NavHeaderbar = function(config){
3771 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3775 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3782 desktopCenter : false,
3785 getAutoCreate : function(){
3788 tag: this.nav || 'nav',
3795 if (this.desktopCenter) {
3796 cn.push({cls : 'container', cn : []});
3803 cls: 'navbar-header',
3808 cls: 'navbar-toggle',
3809 'data-toggle': 'collapse',
3814 html: 'Toggle navigation'
3836 cls: 'collapse navbar-collapse',
3840 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3842 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3843 cfg.cls += ' navbar-' + this.position;
3845 // tag can override this..
3847 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3850 if (this.brand !== '') {
3853 href: this.brand_href ? this.brand_href : '#',
3854 cls: 'navbar-brand',
3862 cfg.cls += ' main-nav';
3870 getHeaderChildContainer : function()
3872 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3873 return this.el.select('.navbar-header',true).first();
3876 return this.getChildContainer();
3880 initEvents : function()
3882 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3884 if (this.autohide) {
3889 Roo.get(document).on('scroll',function(e) {
3890 var ns = Roo.get(document).getScroll().top;
3891 var os = prevScroll;
3895 ft.removeClass('slideDown');
3896 ft.addClass('slideUp');
3899 ft.removeClass('slideUp');
3900 ft.addClass('slideDown');
3921 * @class Roo.bootstrap.NavSidebar
3922 * @extends Roo.bootstrap.Navbar
3923 * Bootstrap Sidebar class
3926 * Create a new Sidebar
3927 * @param {Object} config The config object
3931 Roo.bootstrap.NavSidebar = function(config){
3932 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3935 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3937 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3939 getAutoCreate : function(){
3944 cls: 'sidebar sidebar-nav'
3966 * @class Roo.bootstrap.NavGroup
3967 * @extends Roo.bootstrap.Component
3968 * Bootstrap NavGroup class
3969 * @cfg {String} align (left|right)
3970 * @cfg {Boolean} inverse
3971 * @cfg {String} type (nav|pills|tab) default nav
3972 * @cfg {String} navId - reference Id for navbar.
3976 * Create a new nav group
3977 * @param {Object} config The config object
3980 Roo.bootstrap.NavGroup = function(config){
3981 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3984 Roo.bootstrap.NavGroup.register(this);
3988 * Fires when the active item changes
3989 * @param {Roo.bootstrap.NavGroup} this
3990 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3991 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3998 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4009 getAutoCreate : function()
4011 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4018 if (['tabs','pills'].indexOf(this.type)!==-1) {
4019 cfg.cls += ' nav-' + this.type
4021 if (this.type!=='nav') {
4022 Roo.log('nav type must be nav/tabs/pills')
4024 cfg.cls += ' navbar-nav'
4027 if (this.parent() && this.parent().sidebar) {
4030 cls: 'dashboard-menu sidebar-menu'
4036 if (this.form === true) {
4042 if (this.align === 'right') {
4043 cfg.cls += ' navbar-right';
4045 cfg.cls += ' navbar-left';
4049 if (this.align === 'right') {
4050 cfg.cls += ' navbar-right';
4054 cfg.cls += ' navbar-inverse';
4062 * sets the active Navigation item
4063 * @param {Roo.bootstrap.NavItem} the new current navitem
4065 setActiveItem : function(item)
4068 Roo.each(this.navItems, function(v){
4073 v.setActive(false, true);
4080 item.setActive(true, true);
4081 this.fireEvent('changed', this, item, prev);
4086 * gets the active Navigation item
4087 * @return {Roo.bootstrap.NavItem} the current navitem
4089 getActive : function()
4093 Roo.each(this.navItems, function(v){
4104 indexOfNav : function()
4108 Roo.each(this.navItems, function(v,i){
4119 * adds a Navigation item
4120 * @param {Roo.bootstrap.NavItem} the navitem to add
4122 addItem : function(cfg)
4124 var cn = new Roo.bootstrap.NavItem(cfg);
4126 cn.parentId = this.id;
4127 cn.onRender(this.el, null);
4131 * register a Navigation item
4132 * @param {Roo.bootstrap.NavItem} the navitem to add
4134 register : function(item)
4136 this.navItems.push( item);
4137 item.navId = this.navId;
4142 * clear all the Navigation item
4145 clearAll : function()
4148 this.el.dom.innerHTML = '';
4151 getNavItem: function(tabId)
4154 Roo.each(this.navItems, function(e) {
4155 if (e.tabId == tabId) {
4165 setActiveNext : function()
4167 var i = this.indexOfNav(this.getActive());
4168 if (i > this.navItems.length) {
4171 this.setActiveItem(this.navItems[i+1]);
4173 setActivePrev : function()
4175 var i = this.indexOfNav(this.getActive());
4179 this.setActiveItem(this.navItems[i-1]);
4181 clearWasActive : function(except) {
4182 Roo.each(this.navItems, function(e) {
4183 if (e.tabId != except.tabId && e.was_active) {
4184 e.was_active = false;
4191 getWasActive : function ()
4194 Roo.each(this.navItems, function(e) {
4209 Roo.apply(Roo.bootstrap.NavGroup, {
4213 * register a Navigation Group
4214 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4216 register : function(navgrp)
4218 this.groups[navgrp.navId] = navgrp;
4222 * fetch a Navigation Group based on the navigation ID
4223 * @param {string} the navgroup to add
4224 * @returns {Roo.bootstrap.NavGroup} the navgroup
4226 get: function(navId) {
4227 if (typeof(this.groups[navId]) == 'undefined') {
4229 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4231 return this.groups[navId] ;
4246 * @class Roo.bootstrap.NavItem
4247 * @extends Roo.bootstrap.Component
4248 * Bootstrap Navbar.NavItem class
4249 * @cfg {String} href link to
4250 * @cfg {String} html content of button
4251 * @cfg {String} badge text inside badge
4252 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4253 * @cfg {String} glyphicon name of glyphicon
4254 * @cfg {String} icon name of font awesome icon
4255 * @cfg {Boolean} active Is item active
4256 * @cfg {Boolean} disabled Is item disabled
4258 * @cfg {Boolean} preventDefault (true | false) default false
4259 * @cfg {String} tabId the tab that this item activates.
4260 * @cfg {String} tagtype (a|span) render as a href or span?
4261 * @cfg {Boolean} animateRef (true|false) link to element default false
4264 * Create a new Navbar Item
4265 * @param {Object} config The config object
4267 Roo.bootstrap.NavItem = function(config){
4268 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4273 * The raw click event for the entire grid.
4274 * @param {Roo.EventObject} e
4279 * Fires when the active item active state changes
4280 * @param {Roo.bootstrap.NavItem} this
4281 * @param {boolean} state the new state
4287 * Fires when scroll to element
4288 * @param {Roo.bootstrap.NavItem} this
4289 * @param {Object} options
4290 * @param {Roo.EventObject} e
4298 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4306 preventDefault : false,
4313 getAutoCreate : function(){
4322 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4324 if (this.disabled) {
4325 cfg.cls += ' disabled';
4328 if (this.href || this.html || this.glyphicon || this.icon) {
4332 href : this.href || "#",
4333 html: this.html || ''
4338 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4341 if(this.glyphicon) {
4342 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4347 cfg.cn[0].html += " <span class='caret'></span>";
4351 if (this.badge !== '') {
4353 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4361 initEvents: function()
4363 if (typeof (this.menu) != 'undefined') {
4364 this.menu.parentType = this.xtype;
4365 this.menu.triggerEl = this.el;
4366 this.menu = this.addxtype(Roo.apply({}, this.menu));
4369 this.el.select('a',true).on('click', this.onClick, this);
4371 if(this.tagtype == 'span'){
4372 this.el.select('span',true).on('click', this.onClick, this);
4375 // at this point parent should be available..
4376 this.parent().register(this);
4379 onClick : function(e)
4381 if (e.getTarget('.dropdown-menu-item')) {
4382 // did you click on a menu itemm.... - then don't trigger onclick..
4387 this.preventDefault ||
4390 Roo.log("NavItem - prevent Default?");
4394 if (this.disabled) {
4398 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4399 if (tg && tg.transition) {
4400 Roo.log("waiting for the transitionend");
4406 //Roo.log("fire event clicked");
4407 if(this.fireEvent('click', this, e) === false){
4411 if(this.tagtype == 'span'){
4415 //Roo.log(this.href);
4416 var ael = this.el.select('a',true).first();
4419 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4420 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4421 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4422 return; // ignore... - it's a 'hash' to another page.
4424 Roo.log("NavItem - prevent Default?");
4426 this.scrollToElement(e);
4430 var p = this.parent();
4432 if (['tabs','pills'].indexOf(p.type)!==-1) {
4433 if (typeof(p.setActiveItem) !== 'undefined') {
4434 p.setActiveItem(this);
4438 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4439 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4440 // remove the collapsed menu expand...
4441 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4445 isActive: function () {
4448 setActive : function(state, fire, is_was_active)
4450 if (this.active && !state && this.navId) {
4451 this.was_active = true;
4452 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4454 nv.clearWasActive(this);
4458 this.active = state;
4461 this.el.removeClass('active');
4462 } else if (!this.el.hasClass('active')) {
4463 this.el.addClass('active');
4466 this.fireEvent('changed', this, state);
4469 // show a panel if it's registered and related..
4471 if (!this.navId || !this.tabId || !state || is_was_active) {
4475 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4479 var pan = tg.getPanelByName(this.tabId);
4483 // if we can not flip to new panel - go back to old nav highlight..
4484 if (false == tg.showPanel(pan)) {
4485 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4487 var onav = nv.getWasActive();
4489 onav.setActive(true, false, true);
4498 // this should not be here...
4499 setDisabled : function(state)
4501 this.disabled = state;
4503 this.el.removeClass('disabled');
4504 } else if (!this.el.hasClass('disabled')) {
4505 this.el.addClass('disabled');
4511 * Fetch the element to display the tooltip on.
4512 * @return {Roo.Element} defaults to this.el
4514 tooltipEl : function()
4516 return this.el.select('' + this.tagtype + '', true).first();
4519 scrollToElement : function(e)
4521 var c = document.body;
4524 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4526 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4527 c = document.documentElement;
4530 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4536 var o = target.calcOffsetsTo(c);
4543 this.fireEvent('scrollto', this, options, e);
4545 Roo.get(c).scrollTo('top', options.value, true);
4558 * <span> icon </span>
4559 * <span> text </span>
4560 * <span>badge </span>
4564 * @class Roo.bootstrap.NavSidebarItem
4565 * @extends Roo.bootstrap.NavItem
4566 * Bootstrap Navbar.NavSidebarItem class
4567 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4568 * {Boolean} open is the menu open
4569 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4570 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4571 * {String} buttonSize (sm|md|lg)the extra classes for the button
4572 * {Boolean} showArrow show arrow next to the text (default true)
4574 * Create a new Navbar Button
4575 * @param {Object} config The config object
4577 Roo.bootstrap.NavSidebarItem = function(config){
4578 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4583 * The raw click event for the entire grid.
4584 * @param {Roo.EventObject} e
4589 * Fires when the active item active state changes
4590 * @param {Roo.bootstrap.NavSidebarItem} this
4591 * @param {boolean} state the new state
4599 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4601 badgeWeight : 'default',
4607 buttonWeight : 'default',
4613 getAutoCreate : function(){
4618 href : this.href || '#',
4624 if(this.buttonView){
4627 href : this.href || '#',
4628 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4641 cfg.cls += ' active';
4644 if (this.disabled) {
4645 cfg.cls += ' disabled';
4648 cfg.cls += ' open x-open';
4651 if (this.glyphicon || this.icon) {
4652 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4653 a.cn.push({ tag : 'i', cls : c }) ;
4656 if(!this.buttonView){
4659 html : this.html || ''
4666 if (this.badge !== '') {
4667 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4673 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4676 a.cls += ' dropdown-toggle treeview' ;
4682 initEvents : function()
4684 if (typeof (this.menu) != 'undefined') {
4685 this.menu.parentType = this.xtype;
4686 this.menu.triggerEl = this.el;
4687 this.menu = this.addxtype(Roo.apply({}, this.menu));
4690 this.el.on('click', this.onClick, this);
4692 if(this.badge !== ''){
4693 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4698 onClick : function(e)
4705 if(this.preventDefault){
4709 this.fireEvent('click', this);
4712 disable : function()
4714 this.setDisabled(true);
4719 this.setDisabled(false);
4722 setDisabled : function(state)
4724 if(this.disabled == state){
4728 this.disabled = state;
4731 this.el.addClass('disabled');
4735 this.el.removeClass('disabled');
4740 setActive : function(state)
4742 if(this.active == state){
4746 this.active = state;
4749 this.el.addClass('active');
4753 this.el.removeClass('active');
4758 isActive: function ()
4763 setBadge : function(str)
4769 this.badgeEl.dom.innerHTML = str;
4786 * @class Roo.bootstrap.Row
4787 * @extends Roo.bootstrap.Component
4788 * Bootstrap Row class (contains columns...)
4792 * @param {Object} config The config object
4795 Roo.bootstrap.Row = function(config){
4796 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4799 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4801 getAutoCreate : function(){
4820 * @class Roo.bootstrap.Element
4821 * @extends Roo.bootstrap.Component
4822 * Bootstrap Element class
4823 * @cfg {String} html contents of the element
4824 * @cfg {String} tag tag of the element
4825 * @cfg {String} cls class of the element
4826 * @cfg {Boolean} preventDefault (true|false) default false
4827 * @cfg {Boolean} clickable (true|false) default false
4830 * Create a new Element
4831 * @param {Object} config The config object
4834 Roo.bootstrap.Element = function(config){
4835 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4841 * When a element is chick
4842 * @param {Roo.bootstrap.Element} this
4843 * @param {Roo.EventObject} e
4849 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4854 preventDefault: false,
4857 getAutoCreate : function(){
4868 initEvents: function()
4870 Roo.bootstrap.Element.superclass.initEvents.call(this);
4873 this.el.on('click', this.onClick, this);
4878 onClick : function(e)
4880 if(this.preventDefault){
4884 this.fireEvent('click', this, e);
4887 getValue : function()
4889 return this.el.dom.innerHTML;
4892 setValue : function(value)
4894 this.el.dom.innerHTML = value;
4909 * @class Roo.bootstrap.Pagination
4910 * @extends Roo.bootstrap.Component
4911 * Bootstrap Pagination class
4912 * @cfg {String} size xs | sm | md | lg
4913 * @cfg {Boolean} inverse false | true
4916 * Create a new Pagination
4917 * @param {Object} config The config object
4920 Roo.bootstrap.Pagination = function(config){
4921 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4924 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4930 getAutoCreate : function(){
4936 cfg.cls += ' inverse';
4942 cfg.cls += " " + this.cls;
4960 * @class Roo.bootstrap.PaginationItem
4961 * @extends Roo.bootstrap.Component
4962 * Bootstrap PaginationItem class
4963 * @cfg {String} html text
4964 * @cfg {String} href the link
4965 * @cfg {Boolean} preventDefault (true | false) default true
4966 * @cfg {Boolean} active (true | false) default false
4967 * @cfg {Boolean} disabled default false
4971 * Create a new PaginationItem
4972 * @param {Object} config The config object
4976 Roo.bootstrap.PaginationItem = function(config){
4977 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4982 * The raw click event for the entire grid.
4983 * @param {Roo.EventObject} e
4989 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4993 preventDefault: true,
4998 getAutoCreate : function(){
5004 href : this.href ? this.href : '#',
5005 html : this.html ? this.html : ''
5015 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5019 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5025 initEvents: function() {
5027 this.el.on('click', this.onClick, this);
5030 onClick : function(e)
5032 Roo.log('PaginationItem on click ');
5033 if(this.preventDefault){
5041 this.fireEvent('click', this, e);
5057 * @class Roo.bootstrap.Slider
5058 * @extends Roo.bootstrap.Component
5059 * Bootstrap Slider class
5062 * Create a new Slider
5063 * @param {Object} config The config object
5066 Roo.bootstrap.Slider = function(config){
5067 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5070 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5072 getAutoCreate : function(){
5076 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5080 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5092 * Ext JS Library 1.1.1
5093 * Copyright(c) 2006-2007, Ext JS, LLC.
5095 * Originally Released Under LGPL - original licence link has changed is not relivant.
5098 * <script type="text/javascript">
5103 * @class Roo.grid.ColumnModel
5104 * @extends Roo.util.Observable
5105 * This is the default implementation of a ColumnModel used by the Grid. It defines
5106 * the columns in the grid.
5109 var colModel = new Roo.grid.ColumnModel([
5110 {header: "Ticker", width: 60, sortable: true, locked: true},
5111 {header: "Company Name", width: 150, sortable: true},
5112 {header: "Market Cap.", width: 100, sortable: true},
5113 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5114 {header: "Employees", width: 100, sortable: true, resizable: false}
5119 * The config options listed for this class are options which may appear in each
5120 * individual column definition.
5121 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5123 * @param {Object} config An Array of column config objects. See this class's
5124 * config objects for details.
5126 Roo.grid.ColumnModel = function(config){
5128 * The config passed into the constructor
5130 this.config = config;
5133 // if no id, create one
5134 // if the column does not have a dataIndex mapping,
5135 // map it to the order it is in the config
5136 for(var i = 0, len = config.length; i < len; i++){
5138 if(typeof c.dataIndex == "undefined"){
5141 if(typeof c.renderer == "string"){
5142 c.renderer = Roo.util.Format[c.renderer];
5144 if(typeof c.id == "undefined"){
5147 if(c.editor && c.editor.xtype){
5148 c.editor = Roo.factory(c.editor, Roo.grid);
5150 if(c.editor && c.editor.isFormField){
5151 c.editor = new Roo.grid.GridEditor(c.editor);
5153 this.lookup[c.id] = c;
5157 * The width of columns which have no width specified (defaults to 100)
5160 this.defaultWidth = 100;
5163 * Default sortable of columns which have no sortable specified (defaults to false)
5166 this.defaultSortable = false;
5170 * @event widthchange
5171 * Fires when the width of a column changes.
5172 * @param {ColumnModel} this
5173 * @param {Number} columnIndex The column index
5174 * @param {Number} newWidth The new width
5176 "widthchange": true,
5178 * @event headerchange
5179 * Fires when the text of a header changes.
5180 * @param {ColumnModel} this
5181 * @param {Number} columnIndex The column index
5182 * @param {Number} newText The new header text
5184 "headerchange": true,
5186 * @event hiddenchange
5187 * Fires when a column is hidden or "unhidden".
5188 * @param {ColumnModel} this
5189 * @param {Number} columnIndex The column index
5190 * @param {Boolean} hidden true if hidden, false otherwise
5192 "hiddenchange": true,
5194 * @event columnmoved
5195 * Fires when a column is moved.
5196 * @param {ColumnModel} this
5197 * @param {Number} oldIndex
5198 * @param {Number} newIndex
5200 "columnmoved" : true,
5202 * @event columlockchange
5203 * Fires when a column's locked state is changed
5204 * @param {ColumnModel} this
5205 * @param {Number} colIndex
5206 * @param {Boolean} locked true if locked
5208 "columnlockchange" : true
5210 Roo.grid.ColumnModel.superclass.constructor.call(this);
5212 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5214 * @cfg {String} header The header text to display in the Grid view.
5217 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5218 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5219 * specified, the column's index is used as an index into the Record's data Array.
5222 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5223 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5226 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5227 * Defaults to the value of the {@link #defaultSortable} property.
5228 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5231 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5234 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5237 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5240 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5243 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5244 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5245 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5246 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5249 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5252 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5255 * @cfg {String} cursor (Optional)
5258 * @cfg {String} tooltip (Optional)
5261 * @cfg {Number} xs (Optional)
5264 * @cfg {Number} sm (Optional)
5267 * @cfg {Number} md (Optional)
5270 * @cfg {Number} lg (Optional)
5273 * Returns the id of the column at the specified index.
5274 * @param {Number} index The column index
5275 * @return {String} the id
5277 getColumnId : function(index){
5278 return this.config[index].id;
5282 * Returns the column for a specified id.
5283 * @param {String} id The column id
5284 * @return {Object} the column
5286 getColumnById : function(id){
5287 return this.lookup[id];
5292 * Returns the column for a specified dataIndex.
5293 * @param {String} dataIndex The column dataIndex
5294 * @return {Object|Boolean} the column or false if not found
5296 getColumnByDataIndex: function(dataIndex){
5297 var index = this.findColumnIndex(dataIndex);
5298 return index > -1 ? this.config[index] : false;
5302 * Returns the index for a specified column id.
5303 * @param {String} id The column id
5304 * @return {Number} the index, or -1 if not found
5306 getIndexById : function(id){
5307 for(var i = 0, len = this.config.length; i < len; i++){
5308 if(this.config[i].id == id){
5316 * Returns the index for a specified column dataIndex.
5317 * @param {String} dataIndex The column dataIndex
5318 * @return {Number} the index, or -1 if not found
5321 findColumnIndex : function(dataIndex){
5322 for(var i = 0, len = this.config.length; i < len; i++){
5323 if(this.config[i].dataIndex == dataIndex){
5331 moveColumn : function(oldIndex, newIndex){
5332 var c = this.config[oldIndex];
5333 this.config.splice(oldIndex, 1);
5334 this.config.splice(newIndex, 0, c);
5335 this.dataMap = null;
5336 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5339 isLocked : function(colIndex){
5340 return this.config[colIndex].locked === true;
5343 setLocked : function(colIndex, value, suppressEvent){
5344 if(this.isLocked(colIndex) == value){
5347 this.config[colIndex].locked = value;
5349 this.fireEvent("columnlockchange", this, colIndex, value);
5353 getTotalLockedWidth : function(){
5355 for(var i = 0; i < this.config.length; i++){
5356 if(this.isLocked(i) && !this.isHidden(i)){
5357 this.totalWidth += this.getColumnWidth(i);
5363 getLockedCount : function(){
5364 for(var i = 0, len = this.config.length; i < len; i++){
5365 if(!this.isLocked(i)){
5370 return this.config.length;
5374 * Returns the number of columns.
5377 getColumnCount : function(visibleOnly){
5378 if(visibleOnly === true){
5380 for(var i = 0, len = this.config.length; i < len; i++){
5381 if(!this.isHidden(i)){
5387 return this.config.length;
5391 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5392 * @param {Function} fn
5393 * @param {Object} scope (optional)
5394 * @return {Array} result
5396 getColumnsBy : function(fn, scope){
5398 for(var i = 0, len = this.config.length; i < len; i++){
5399 var c = this.config[i];
5400 if(fn.call(scope||this, c, i) === true){
5408 * Returns true if the specified column is sortable.
5409 * @param {Number} col The column index
5412 isSortable : function(col){
5413 if(typeof this.config[col].sortable == "undefined"){
5414 return this.defaultSortable;
5416 return this.config[col].sortable;
5420 * Returns the rendering (formatting) function defined for the column.
5421 * @param {Number} col The column index.
5422 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5424 getRenderer : function(col){
5425 if(!this.config[col].renderer){
5426 return Roo.grid.ColumnModel.defaultRenderer;
5428 return this.config[col].renderer;
5432 * Sets the rendering (formatting) function for a column.
5433 * @param {Number} col The column index
5434 * @param {Function} fn The function to use to process the cell's raw data
5435 * to return HTML markup for the grid view. The render function is called with
5436 * the following parameters:<ul>
5437 * <li>Data value.</li>
5438 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5439 * <li>css A CSS style string to apply to the table cell.</li>
5440 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5441 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5442 * <li>Row index</li>
5443 * <li>Column index</li>
5444 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5446 setRenderer : function(col, fn){
5447 this.config[col].renderer = fn;
5451 * Returns the width for the specified column.
5452 * @param {Number} col The column index
5455 getColumnWidth : function(col){
5456 return this.config[col].width * 1 || this.defaultWidth;
5460 * Sets the width for a column.
5461 * @param {Number} col The column index
5462 * @param {Number} width The new width
5464 setColumnWidth : function(col, width, suppressEvent){
5465 this.config[col].width = width;
5466 this.totalWidth = null;
5468 this.fireEvent("widthchange", this, col, width);
5473 * Returns the total width of all columns.
5474 * @param {Boolean} includeHidden True to include hidden column widths
5477 getTotalWidth : function(includeHidden){
5478 if(!this.totalWidth){
5479 this.totalWidth = 0;
5480 for(var i = 0, len = this.config.length; i < len; i++){
5481 if(includeHidden || !this.isHidden(i)){
5482 this.totalWidth += this.getColumnWidth(i);
5486 return this.totalWidth;
5490 * Returns the header for the specified column.
5491 * @param {Number} col The column index
5494 getColumnHeader : function(col){
5495 return this.config[col].header;
5499 * Sets the header for a column.
5500 * @param {Number} col The column index
5501 * @param {String} header The new header
5503 setColumnHeader : function(col, header){
5504 this.config[col].header = header;
5505 this.fireEvent("headerchange", this, col, header);
5509 * Returns the tooltip for the specified column.
5510 * @param {Number} col The column index
5513 getColumnTooltip : function(col){
5514 return this.config[col].tooltip;
5517 * Sets the tooltip for a column.
5518 * @param {Number} col The column index
5519 * @param {String} tooltip The new tooltip
5521 setColumnTooltip : function(col, tooltip){
5522 this.config[col].tooltip = tooltip;
5526 * Returns the dataIndex for the specified column.
5527 * @param {Number} col The column index
5530 getDataIndex : function(col){
5531 return this.config[col].dataIndex;
5535 * Sets the dataIndex for a column.
5536 * @param {Number} col The column index
5537 * @param {Number} dataIndex The new dataIndex
5539 setDataIndex : function(col, dataIndex){
5540 this.config[col].dataIndex = dataIndex;
5546 * Returns true if the cell is editable.
5547 * @param {Number} colIndex The column index
5548 * @param {Number} rowIndex The row index - this is nto actually used..?
5551 isCellEditable : function(colIndex, rowIndex){
5552 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5556 * Returns the editor defined for the cell/column.
5557 * return false or null to disable editing.
5558 * @param {Number} colIndex The column index
5559 * @param {Number} rowIndex The row index
5562 getCellEditor : function(colIndex, rowIndex){
5563 return this.config[colIndex].editor;
5567 * Sets if a column is editable.
5568 * @param {Number} col The column index
5569 * @param {Boolean} editable True if the column is editable
5571 setEditable : function(col, editable){
5572 this.config[col].editable = editable;
5577 * Returns true if the column is hidden.
5578 * @param {Number} colIndex The column index
5581 isHidden : function(colIndex){
5582 return this.config[colIndex].hidden;
5587 * Returns true if the column width cannot be changed
5589 isFixed : function(colIndex){
5590 return this.config[colIndex].fixed;
5594 * Returns true if the column can be resized
5597 isResizable : function(colIndex){
5598 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5601 * Sets if a column is hidden.
5602 * @param {Number} colIndex The column index
5603 * @param {Boolean} hidden True if the column is hidden
5605 setHidden : function(colIndex, hidden){
5606 this.config[colIndex].hidden = hidden;
5607 this.totalWidth = null;
5608 this.fireEvent("hiddenchange", this, colIndex, hidden);
5612 * Sets the editor for a column.
5613 * @param {Number} col The column index
5614 * @param {Object} editor The editor object
5616 setEditor : function(col, editor){
5617 this.config[col].editor = editor;
5621 Roo.grid.ColumnModel.defaultRenderer = function(value)
5623 if(typeof value == "object") {
5626 if(typeof value == "string" && value.length < 1){
5630 return String.format("{0}", value);
5633 // Alias for backwards compatibility
5634 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5637 * Ext JS Library 1.1.1
5638 * Copyright(c) 2006-2007, Ext JS, LLC.
5640 * Originally Released Under LGPL - original licence link has changed is not relivant.
5643 * <script type="text/javascript">
5647 * @class Roo.LoadMask
5648 * A simple utility class for generically masking elements while loading data. If the element being masked has
5649 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5650 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5651 * element's UpdateManager load indicator and will be destroyed after the initial load.
5653 * Create a new LoadMask
5654 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5655 * @param {Object} config The config object
5657 Roo.LoadMask = function(el, config){
5658 this.el = Roo.get(el);
5659 Roo.apply(this, config);
5661 this.store.on('beforeload', this.onBeforeLoad, this);
5662 this.store.on('load', this.onLoad, this);
5663 this.store.on('loadexception', this.onLoadException, this);
5664 this.removeMask = false;
5666 var um = this.el.getUpdateManager();
5667 um.showLoadIndicator = false; // disable the default indicator
5668 um.on('beforeupdate', this.onBeforeLoad, this);
5669 um.on('update', this.onLoad, this);
5670 um.on('failure', this.onLoad, this);
5671 this.removeMask = true;
5675 Roo.LoadMask.prototype = {
5677 * @cfg {Boolean} removeMask
5678 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5679 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5683 * The text to display in a centered loading message box (defaults to 'Loading...')
5687 * @cfg {String} msgCls
5688 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5690 msgCls : 'x-mask-loading',
5693 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5699 * Disables the mask to prevent it from being displayed
5701 disable : function(){
5702 this.disabled = true;
5706 * Enables the mask so that it can be displayed
5708 enable : function(){
5709 this.disabled = false;
5712 onLoadException : function()
5716 if (typeof(arguments[3]) != 'undefined') {
5717 Roo.MessageBox.alert("Error loading",arguments[3]);
5721 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5722 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5729 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5734 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5738 onBeforeLoad : function(){
5740 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5745 destroy : function(){
5747 this.store.un('beforeload', this.onBeforeLoad, this);
5748 this.store.un('load', this.onLoad, this);
5749 this.store.un('loadexception', this.onLoadException, this);
5751 var um = this.el.getUpdateManager();
5752 um.un('beforeupdate', this.onBeforeLoad, this);
5753 um.un('update', this.onLoad, this);
5754 um.un('failure', this.onLoad, this);
5765 * @class Roo.bootstrap.Table
5766 * @extends Roo.bootstrap.Component
5767 * Bootstrap Table class
5768 * @cfg {String} cls table class
5769 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5770 * @cfg {String} bgcolor Specifies the background color for a table
5771 * @cfg {Number} border Specifies whether the table cells should have borders or not
5772 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5773 * @cfg {Number} cellspacing Specifies the space between cells
5774 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5775 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5776 * @cfg {String} sortable Specifies that the table should be sortable
5777 * @cfg {String} summary Specifies a summary of the content of a table
5778 * @cfg {Number} width Specifies the width of a table
5779 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5781 * @cfg {boolean} striped Should the rows be alternative striped
5782 * @cfg {boolean} bordered Add borders to the table
5783 * @cfg {boolean} hover Add hover highlighting
5784 * @cfg {boolean} condensed Format condensed
5785 * @cfg {boolean} responsive Format condensed
5786 * @cfg {Boolean} loadMask (true|false) default false
5787 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5788 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5789 * @cfg {Boolean} rowSelection (true|false) default false
5790 * @cfg {Boolean} cellSelection (true|false) default false
5791 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5792 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5793 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5797 * Create a new Table
5798 * @param {Object} config The config object
5801 Roo.bootstrap.Table = function(config){
5802 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5807 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5808 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5809 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5810 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5812 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5814 this.sm.grid = this;
5815 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5816 this.sm = this.selModel;
5817 this.sm.xmodule = this.xmodule || false;
5820 if (this.cm && typeof(this.cm.config) == 'undefined') {
5821 this.colModel = new Roo.grid.ColumnModel(this.cm);
5822 this.cm = this.colModel;
5823 this.cm.xmodule = this.xmodule || false;
5826 this.store= Roo.factory(this.store, Roo.data);
5827 this.ds = this.store;
5828 this.ds.xmodule = this.xmodule || false;
5831 if (this.footer && this.store) {
5832 this.footer.dataSource = this.ds;
5833 this.footer = Roo.factory(this.footer);
5840 * Fires when a cell is clicked
5841 * @param {Roo.bootstrap.Table} this
5842 * @param {Roo.Element} el
5843 * @param {Number} rowIndex
5844 * @param {Number} columnIndex
5845 * @param {Roo.EventObject} e
5849 * @event celldblclick
5850 * Fires when a cell is double clicked
5851 * @param {Roo.bootstrap.Table} this
5852 * @param {Roo.Element} el
5853 * @param {Number} rowIndex
5854 * @param {Number} columnIndex
5855 * @param {Roo.EventObject} e
5857 "celldblclick" : true,
5860 * Fires when a row is clicked
5861 * @param {Roo.bootstrap.Table} this
5862 * @param {Roo.Element} el
5863 * @param {Number} rowIndex
5864 * @param {Roo.EventObject} e
5868 * @event rowdblclick
5869 * Fires when a row is double clicked
5870 * @param {Roo.bootstrap.Table} this
5871 * @param {Roo.Element} el
5872 * @param {Number} rowIndex
5873 * @param {Roo.EventObject} e
5875 "rowdblclick" : true,
5878 * Fires when a mouseover occur
5879 * @param {Roo.bootstrap.Table} this
5880 * @param {Roo.Element} el
5881 * @param {Number} rowIndex
5882 * @param {Number} columnIndex
5883 * @param {Roo.EventObject} e
5888 * Fires when a mouseout occur
5889 * @param {Roo.bootstrap.Table} this
5890 * @param {Roo.Element} el
5891 * @param {Number} rowIndex
5892 * @param {Number} columnIndex
5893 * @param {Roo.EventObject} e
5898 * Fires when a row is rendered, so you can change add a style to it.
5899 * @param {Roo.bootstrap.Table} this
5900 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5904 * @event rowsrendered
5905 * Fires when all the rows have been rendered
5906 * @param {Roo.bootstrap.Table} this
5908 'rowsrendered' : true,
5910 * @event contextmenu
5911 * The raw contextmenu event for the entire grid.
5912 * @param {Roo.EventObject} e
5914 "contextmenu" : true,
5916 * @event rowcontextmenu
5917 * Fires when a row is right clicked
5918 * @param {Roo.bootstrap.Table} this
5919 * @param {Number} rowIndex
5920 * @param {Roo.EventObject} e
5922 "rowcontextmenu" : true,
5924 * @event cellcontextmenu
5925 * Fires when a cell is right clicked
5926 * @param {Roo.bootstrap.Table} this
5927 * @param {Number} rowIndex
5928 * @param {Number} cellIndex
5929 * @param {Roo.EventObject} e
5931 "cellcontextmenu" : true,
5933 * @event headercontextmenu
5934 * Fires when a header is right clicked
5935 * @param {Roo.bootstrap.Table} this
5936 * @param {Number} columnIndex
5937 * @param {Roo.EventObject} e
5939 "headercontextmenu" : true
5943 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5969 rowSelection : false,
5970 cellSelection : false,
5973 // Roo.Element - the tbody
5975 // Roo.Element - thead element
5978 container: false, // used by gridpanel...
5982 getAutoCreate : function()
5984 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5991 if (this.scrollBody) {
5992 cfg.cls += ' table-body-fixed';
5995 cfg.cls += ' table-striped';
5999 cfg.cls += ' table-hover';
6001 if (this.bordered) {
6002 cfg.cls += ' table-bordered';
6004 if (this.condensed) {
6005 cfg.cls += ' table-condensed';
6007 if (this.responsive) {
6008 cfg.cls += ' table-responsive';
6012 cfg.cls+= ' ' +this.cls;
6015 // this lot should be simplifed...
6018 cfg.align=this.align;
6021 cfg.bgcolor=this.bgcolor;
6024 cfg.border=this.border;
6026 if (this.cellpadding) {
6027 cfg.cellpadding=this.cellpadding;
6029 if (this.cellspacing) {
6030 cfg.cellspacing=this.cellspacing;
6033 cfg.frame=this.frame;
6036 cfg.rules=this.rules;
6038 if (this.sortable) {
6039 cfg.sortable=this.sortable;
6042 cfg.summary=this.summary;
6045 cfg.width=this.width;
6048 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6051 if(this.store || this.cm){
6052 if(this.headerShow){
6053 cfg.cn.push(this.renderHeader());
6056 cfg.cn.push(this.renderBody());
6058 if(this.footerShow){
6059 cfg.cn.push(this.renderFooter());
6061 // where does this come from?
6062 //cfg.cls+= ' TableGrid';
6065 return { cn : [ cfg ] };
6068 initEvents : function()
6070 if(!this.store || !this.cm){
6073 if (this.selModel) {
6074 this.selModel.initEvents();
6078 //Roo.log('initEvents with ds!!!!');
6080 this.mainBody = this.el.select('tbody', true).first();
6081 this.mainHead = this.el.select('thead', true).first();
6088 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6089 e.on('click', _this.sort, _this);
6092 this.mainBody.on("click", this.onClick, this);
6093 this.mainBody.on("dblclick", this.onDblClick, this);
6095 // why is this done????? = it breaks dialogs??
6096 //this.parent().el.setStyle('position', 'relative');
6100 this.footer.parentId = this.id;
6101 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6104 this.el.select('tfoot tr td').first().addClass('hide');
6108 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6110 this.store.on('load', this.onLoad, this);
6111 this.store.on('beforeload', this.onBeforeLoad, this);
6112 this.store.on('update', this.onUpdate, this);
6113 this.store.on('add', this.onAdd, this);
6114 this.store.on("clear", this.clear, this);
6116 this.el.on("contextmenu", this.onContextMenu, this);
6118 this.mainBody.on('scroll', this.onBodyScroll, this);
6123 onContextMenu : function(e, t)
6125 this.processEvent("contextmenu", e);
6128 processEvent : function(name, e)
6130 if (name != 'touchstart' ) {
6131 this.fireEvent(name, e);
6134 var t = e.getTarget();
6136 var cell = Roo.get(t);
6142 if(cell.findParent('tfoot', false, true)){
6146 if(cell.findParent('thead', false, true)){
6148 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6149 cell = Roo.get(t).findParent('th', false, true);
6151 Roo.log("failed to find th in thead?");
6152 Roo.log(e.getTarget());
6157 var cellIndex = cell.dom.cellIndex;
6159 var ename = name == 'touchstart' ? 'click' : name;
6160 this.fireEvent("header" + ename, this, cellIndex, e);
6165 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6166 cell = Roo.get(t).findParent('td', false, true);
6168 Roo.log("failed to find th in tbody?");
6169 Roo.log(e.getTarget());
6174 var row = cell.findParent('tr', false, true);
6175 var cellIndex = cell.dom.cellIndex;
6176 var rowIndex = row.dom.rowIndex - 1;
6180 this.fireEvent("row" + name, this, rowIndex, e);
6184 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6190 onMouseover : function(e, el)
6192 var cell = Roo.get(el);
6198 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6199 cell = cell.findParent('td', false, true);
6202 var row = cell.findParent('tr', false, true);
6203 var cellIndex = cell.dom.cellIndex;
6204 var rowIndex = row.dom.rowIndex - 1; // start from 0
6206 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6210 onMouseout : function(e, el)
6212 var cell = Roo.get(el);
6218 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6219 cell = cell.findParent('td', false, true);
6222 var row = cell.findParent('tr', false, true);
6223 var cellIndex = cell.dom.cellIndex;
6224 var rowIndex = row.dom.rowIndex - 1; // start from 0
6226 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6230 onClick : function(e, el)
6232 var cell = Roo.get(el);
6234 if(!cell || (!this.cellSelection && !this.rowSelection)){
6238 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6239 cell = cell.findParent('td', false, true);
6242 if(!cell || typeof(cell) == 'undefined'){
6246 var row = cell.findParent('tr', false, true);
6248 if(!row || typeof(row) == 'undefined'){
6252 var cellIndex = cell.dom.cellIndex;
6253 var rowIndex = this.getRowIndex(row);
6255 // why??? - should these not be based on SelectionModel?
6256 if(this.cellSelection){
6257 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6260 if(this.rowSelection){
6261 this.fireEvent('rowclick', this, row, rowIndex, e);
6267 onDblClick : function(e,el)
6269 var cell = Roo.get(el);
6271 if(!cell || (!this.cellSelection && !this.rowSelection)){
6275 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6276 cell = cell.findParent('td', false, true);
6279 if(!cell || typeof(cell) == 'undefined'){
6283 var row = cell.findParent('tr', false, true);
6285 if(!row || typeof(row) == 'undefined'){
6289 var cellIndex = cell.dom.cellIndex;
6290 var rowIndex = this.getRowIndex(row);
6292 if(this.cellSelection){
6293 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6296 if(this.rowSelection){
6297 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6301 sort : function(e,el)
6303 var col = Roo.get(el);
6305 if(!col.hasClass('sortable')){
6309 var sort = col.attr('sort');
6312 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6316 this.store.sortInfo = {field : sort, direction : dir};
6319 Roo.log("calling footer first");
6320 this.footer.onClick('first');
6323 this.store.load({ params : { start : 0 } });
6327 renderHeader : function()
6335 this.totalWidth = 0;
6337 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6339 var config = cm.config[i];
6344 html: cm.getColumnHeader(i)
6349 if(typeof(config.sortable) != 'undefined' && config.sortable){
6351 c.html = '<i class="glyphicon"></i>' + c.html;
6354 if(typeof(config.lgHeader) != 'undefined'){
6355 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6358 if(typeof(config.mdHeader) != 'undefined'){
6359 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6362 if(typeof(config.smHeader) != 'undefined'){
6363 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6366 if(typeof(config.xsHeader) != 'undefined'){
6367 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6374 if(typeof(config.tooltip) != 'undefined'){
6375 c.tooltip = config.tooltip;
6378 if(typeof(config.colspan) != 'undefined'){
6379 c.colspan = config.colspan;
6382 if(typeof(config.hidden) != 'undefined' && config.hidden){
6383 c.style += ' display:none;';
6386 if(typeof(config.dataIndex) != 'undefined'){
6387 c.sort = config.dataIndex;
6392 if(typeof(config.align) != 'undefined' && config.align.length){
6393 c.style += ' text-align:' + config.align + ';';
6396 if(typeof(config.width) != 'undefined'){
6397 c.style += ' width:' + config.width + 'px;';
6398 this.totalWidth += config.width;
6400 this.totalWidth += 100; // assume minimum of 100 per column?
6403 if(typeof(config.cls) != 'undefined'){
6404 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6407 ['xs','sm','md','lg'].map(function(size){
6409 if(typeof(config[size]) == 'undefined'){
6413 if (!config[size]) { // 0 = hidden
6414 c.cls += ' hidden-' + size;
6418 c.cls += ' col-' + size + '-' + config[size];
6428 renderBody : function()
6438 colspan : this.cm.getColumnCount()
6448 renderFooter : function()
6458 colspan : this.cm.getColumnCount()
6472 // Roo.log('ds onload');
6477 var ds = this.store;
6479 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6480 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6481 if (_this.store.sortInfo) {
6483 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6484 e.select('i', true).addClass(['glyphicon-arrow-up']);
6487 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6488 e.select('i', true).addClass(['glyphicon-arrow-down']);
6493 var tbody = this.mainBody;
6495 if(ds.getCount() > 0){
6496 ds.data.each(function(d,rowIndex){
6497 var row = this.renderRow(cm, ds, rowIndex);
6499 tbody.createChild(row);
6503 if(row.cellObjects.length){
6504 Roo.each(row.cellObjects, function(r){
6505 _this.renderCellObject(r);
6512 Roo.each(this.el.select('tbody td', true).elements, function(e){
6513 e.on('mouseover', _this.onMouseover, _this);
6516 Roo.each(this.el.select('tbody td', true).elements, function(e){
6517 e.on('mouseout', _this.onMouseout, _this);
6519 this.fireEvent('rowsrendered', this);
6520 //if(this.loadMask){
6521 // this.maskEl.hide();
6528 onUpdate : function(ds,record)
6530 this.refreshRow(record);
6534 onRemove : function(ds, record, index, isUpdate){
6535 if(isUpdate !== true){
6536 this.fireEvent("beforerowremoved", this, index, record);
6538 var bt = this.mainBody.dom;
6540 var rows = this.el.select('tbody > tr', true).elements;
6542 if(typeof(rows[index]) != 'undefined'){
6543 bt.removeChild(rows[index].dom);
6546 // if(bt.rows[index]){
6547 // bt.removeChild(bt.rows[index]);
6550 if(isUpdate !== true){
6551 //this.stripeRows(index);
6552 //this.syncRowHeights(index, index);
6554 this.fireEvent("rowremoved", this, index, record);
6558 onAdd : function(ds, records, rowIndex)
6560 //Roo.log('on Add called');
6561 // - note this does not handle multiple adding very well..
6562 var bt = this.mainBody.dom;
6563 for (var i =0 ; i < records.length;i++) {
6564 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6565 //Roo.log(records[i]);
6566 //Roo.log(this.store.getAt(rowIndex+i));
6567 this.insertRow(this.store, rowIndex + i, false);
6574 refreshRow : function(record){
6575 var ds = this.store, index;
6576 if(typeof record == 'number'){
6578 record = ds.getAt(index);
6580 index = ds.indexOf(record);
6582 this.insertRow(ds, index, true);
6584 this.onRemove(ds, record, index+1, true);
6586 //this.syncRowHeights(index, index);
6588 this.fireEvent("rowupdated", this, index, record);
6591 insertRow : function(dm, rowIndex, isUpdate){
6594 this.fireEvent("beforerowsinserted", this, rowIndex);
6596 //var s = this.getScrollState();
6597 var row = this.renderRow(this.cm, this.store, rowIndex);
6598 // insert before rowIndex..
6599 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6603 if(row.cellObjects.length){
6604 Roo.each(row.cellObjects, function(r){
6605 _this.renderCellObject(r);
6610 this.fireEvent("rowsinserted", this, rowIndex);
6611 //this.syncRowHeights(firstRow, lastRow);
6612 //this.stripeRows(firstRow);
6619 getRowDom : function(rowIndex)
6621 var rows = this.el.select('tbody > tr', true).elements;
6623 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6626 // returns the object tree for a tr..
6629 renderRow : function(cm, ds, rowIndex)
6632 var d = ds.getAt(rowIndex);
6639 var cellObjects = [];
6641 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6642 var config = cm.config[i];
6644 var renderer = cm.getRenderer(i);
6648 if(typeof(renderer) !== 'undefined'){
6649 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6651 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6652 // and are rendered into the cells after the row is rendered - using the id for the element.
6654 if(typeof(value) === 'object'){
6664 rowIndex : rowIndex,
6669 this.fireEvent('rowclass', this, rowcfg);
6673 cls : rowcfg.rowClass,
6675 html: (typeof(value) === 'object') ? '' : value
6682 if(typeof(config.colspan) != 'undefined'){
6683 td.colspan = config.colspan;
6686 if(typeof(config.hidden) != 'undefined' && config.hidden){
6687 td.style += ' display:none;';
6690 if(typeof(config.align) != 'undefined' && config.align.length){
6691 td.style += ' text-align:' + config.align + ';';
6694 if(typeof(config.width) != 'undefined'){
6695 td.style += ' width:' + config.width + 'px;';
6698 if(typeof(config.cursor) != 'undefined'){
6699 td.style += ' cursor:' + config.cursor + ';';
6702 if(typeof(config.cls) != 'undefined'){
6703 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6706 ['xs','sm','md','lg'].map(function(size){
6708 if(typeof(config[size]) == 'undefined'){
6712 if (!config[size]) { // 0 = hidden
6713 td.cls += ' hidden-' + size;
6717 td.cls += ' col-' + size + '-' + config[size];
6725 row.cellObjects = cellObjects;
6733 onBeforeLoad : function()
6735 //Roo.log('ds onBeforeLoad');
6739 //if(this.loadMask){
6740 // this.maskEl.show();
6748 this.el.select('tbody', true).first().dom.innerHTML = '';
6751 * Show or hide a row.
6752 * @param {Number} rowIndex to show or hide
6753 * @param {Boolean} state hide
6755 setRowVisibility : function(rowIndex, state)
6757 var bt = this.mainBody.dom;
6759 var rows = this.el.select('tbody > tr', true).elements;
6761 if(typeof(rows[rowIndex]) == 'undefined'){
6764 rows[rowIndex].dom.style.display = state ? '' : 'none';
6768 getSelectionModel : function(){
6770 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6772 return this.selModel;
6775 * Render the Roo.bootstrap object from renderder
6777 renderCellObject : function(r)
6781 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6783 var t = r.cfg.render(r.container);
6786 Roo.each(r.cfg.cn, function(c){
6788 container: t.getChildContainer(),
6791 _this.renderCellObject(child);
6796 getRowIndex : function(row)
6800 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6811 * Returns the grid's underlying element = used by panel.Grid
6812 * @return {Element} The element
6814 getGridEl : function(){
6818 * Forces a resize - used by panel.Grid
6819 * @return {Element} The element
6821 autoSize : function()
6823 //var ctr = Roo.get(this.container.dom.parentElement);
6824 var ctr = Roo.get(this.el.dom);
6826 var thd = this.getGridEl().select('thead',true).first();
6827 var tbd = this.getGridEl().select('tbody', true).first();
6828 var tfd = this.getGridEl().select('tfoot', true).first();
6830 var cw = ctr.getWidth();
6834 tbd.setSize(ctr.getWidth(),
6835 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6837 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6840 cw = Math.max(cw, this.totalWidth);
6841 this.getGridEl().select('tr',true).setWidth(cw);
6842 // resize 'expandable coloumn?
6844 return; // we doe not have a view in this design..
6847 onBodyScroll: function()
6849 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6850 this.mainHead.setStyle({
6851 'position' : 'relative',
6852 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6857 var scrollHeight = this.mainBody.dom.scrollHeight;
6859 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6861 var height = this.mainBody.getHeight();
6863 if(scrollHeight - height == scrollTop) {
6865 var total = this.ds.getTotalCount();
6867 if(this.footer.cursor + this.footer.pageSize < total){
6869 this.footer.ds.load({
6871 start : this.footer.cursor + this.footer.pageSize,
6872 limit : this.footer.pageSize
6893 * @class Roo.bootstrap.TableCell
6894 * @extends Roo.bootstrap.Component
6895 * Bootstrap TableCell class
6896 * @cfg {String} html cell contain text
6897 * @cfg {String} cls cell class
6898 * @cfg {String} tag cell tag (td|th) default td
6899 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6900 * @cfg {String} align Aligns the content in a cell
6901 * @cfg {String} axis Categorizes cells
6902 * @cfg {String} bgcolor Specifies the background color of a cell
6903 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6904 * @cfg {Number} colspan Specifies the number of columns a cell should span
6905 * @cfg {String} headers Specifies one or more header cells a cell is related to
6906 * @cfg {Number} height Sets the height of a cell
6907 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6908 * @cfg {Number} rowspan Sets the number of rows a cell should span
6909 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6910 * @cfg {String} valign Vertical aligns the content in a cell
6911 * @cfg {Number} width Specifies the width of a cell
6914 * Create a new TableCell
6915 * @param {Object} config The config object
6918 Roo.bootstrap.TableCell = function(config){
6919 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6922 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6942 getAutoCreate : function(){
6943 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6963 cfg.align=this.align
6969 cfg.bgcolor=this.bgcolor
6972 cfg.charoff=this.charoff
6975 cfg.colspan=this.colspan
6978 cfg.headers=this.headers
6981 cfg.height=this.height
6984 cfg.nowrap=this.nowrap
6987 cfg.rowspan=this.rowspan
6990 cfg.scope=this.scope
6993 cfg.valign=this.valign
6996 cfg.width=this.width
7015 * @class Roo.bootstrap.TableRow
7016 * @extends Roo.bootstrap.Component
7017 * Bootstrap TableRow class
7018 * @cfg {String} cls row class
7019 * @cfg {String} align Aligns the content in a table row
7020 * @cfg {String} bgcolor Specifies a background color for a table row
7021 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7022 * @cfg {String} valign Vertical aligns the content in a table row
7025 * Create a new TableRow
7026 * @param {Object} config The config object
7029 Roo.bootstrap.TableRow = function(config){
7030 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7033 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7041 getAutoCreate : function(){
7042 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7052 cfg.align = this.align;
7055 cfg.bgcolor = this.bgcolor;
7058 cfg.charoff = this.charoff;
7061 cfg.valign = this.valign;
7079 * @class Roo.bootstrap.TableBody
7080 * @extends Roo.bootstrap.Component
7081 * Bootstrap TableBody class
7082 * @cfg {String} cls element class
7083 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7084 * @cfg {String} align Aligns the content inside the element
7085 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7086 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7089 * Create a new TableBody
7090 * @param {Object} config The config object
7093 Roo.bootstrap.TableBody = function(config){
7094 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7097 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7105 getAutoCreate : function(){
7106 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7120 cfg.align = this.align;
7123 cfg.charoff = this.charoff;
7126 cfg.valign = this.valign;
7133 // initEvents : function()
7140 // this.store = Roo.factory(this.store, Roo.data);
7141 // this.store.on('load', this.onLoad, this);
7143 // this.store.load();
7147 // onLoad: function ()
7149 // this.fireEvent('load', this);
7159 * Ext JS Library 1.1.1
7160 * Copyright(c) 2006-2007, Ext JS, LLC.
7162 * Originally Released Under LGPL - original licence link has changed is not relivant.
7165 * <script type="text/javascript">
7168 // as we use this in bootstrap.
7169 Roo.namespace('Roo.form');
7171 * @class Roo.form.Action
7172 * Internal Class used to handle form actions
7174 * @param {Roo.form.BasicForm} el The form element or its id
7175 * @param {Object} config Configuration options
7180 // define the action interface
7181 Roo.form.Action = function(form, options){
7183 this.options = options || {};
7186 * Client Validation Failed
7189 Roo.form.Action.CLIENT_INVALID = 'client';
7191 * Server Validation Failed
7194 Roo.form.Action.SERVER_INVALID = 'server';
7196 * Connect to Server Failed
7199 Roo.form.Action.CONNECT_FAILURE = 'connect';
7201 * Reading Data from Server Failed
7204 Roo.form.Action.LOAD_FAILURE = 'load';
7206 Roo.form.Action.prototype = {
7208 failureType : undefined,
7209 response : undefined,
7213 run : function(options){
7218 success : function(response){
7223 handleResponse : function(response){
7227 // default connection failure
7228 failure : function(response){
7230 this.response = response;
7231 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7232 this.form.afterAction(this, false);
7235 processResponse : function(response){
7236 this.response = response;
7237 if(!response.responseText){
7240 this.result = this.handleResponse(response);
7244 // utility functions used internally
7245 getUrl : function(appendParams){
7246 var url = this.options.url || this.form.url || this.form.el.dom.action;
7248 var p = this.getParams();
7250 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7256 getMethod : function(){
7257 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7260 getParams : function(){
7261 var bp = this.form.baseParams;
7262 var p = this.options.params;
7264 if(typeof p == "object"){
7265 p = Roo.urlEncode(Roo.applyIf(p, bp));
7266 }else if(typeof p == 'string' && bp){
7267 p += '&' + Roo.urlEncode(bp);
7270 p = Roo.urlEncode(bp);
7275 createCallback : function(){
7277 success: this.success,
7278 failure: this.failure,
7280 timeout: (this.form.timeout*1000),
7281 upload: this.form.fileUpload ? this.success : undefined
7286 Roo.form.Action.Submit = function(form, options){
7287 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7290 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7293 haveProgress : false,
7294 uploadComplete : false,
7296 // uploadProgress indicator.
7297 uploadProgress : function()
7299 if (!this.form.progressUrl) {
7303 if (!this.haveProgress) {
7304 Roo.MessageBox.progress("Uploading", "Uploading");
7306 if (this.uploadComplete) {
7307 Roo.MessageBox.hide();
7311 this.haveProgress = true;
7313 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7315 var c = new Roo.data.Connection();
7317 url : this.form.progressUrl,
7322 success : function(req){
7323 //console.log(data);
7327 rdata = Roo.decode(req.responseText)
7329 Roo.log("Invalid data from server..");
7333 if (!rdata || !rdata.success) {
7335 Roo.MessageBox.alert(Roo.encode(rdata));
7338 var data = rdata.data;
7340 if (this.uploadComplete) {
7341 Roo.MessageBox.hide();
7346 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7347 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7350 this.uploadProgress.defer(2000,this);
7353 failure: function(data) {
7354 Roo.log('progress url failed ');
7365 // run get Values on the form, so it syncs any secondary forms.
7366 this.form.getValues();
7368 var o = this.options;
7369 var method = this.getMethod();
7370 var isPost = method == 'POST';
7371 if(o.clientValidation === false || this.form.isValid()){
7373 if (this.form.progressUrl) {
7374 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7375 (new Date() * 1) + '' + Math.random());
7380 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7381 form:this.form.el.dom,
7382 url:this.getUrl(!isPost),
7384 params:isPost ? this.getParams() : null,
7385 isUpload: this.form.fileUpload
7388 this.uploadProgress();
7390 }else if (o.clientValidation !== false){ // client validation failed
7391 this.failureType = Roo.form.Action.CLIENT_INVALID;
7392 this.form.afterAction(this, false);
7396 success : function(response)
7398 this.uploadComplete= true;
7399 if (this.haveProgress) {
7400 Roo.MessageBox.hide();
7404 var result = this.processResponse(response);
7405 if(result === true || result.success){
7406 this.form.afterAction(this, true);
7410 this.form.markInvalid(result.errors);
7411 this.failureType = Roo.form.Action.SERVER_INVALID;
7413 this.form.afterAction(this, false);
7415 failure : function(response)
7417 this.uploadComplete= true;
7418 if (this.haveProgress) {
7419 Roo.MessageBox.hide();
7422 this.response = response;
7423 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7424 this.form.afterAction(this, false);
7427 handleResponse : function(response){
7428 if(this.form.errorReader){
7429 var rs = this.form.errorReader.read(response);
7432 for(var i = 0, len = rs.records.length; i < len; i++) {
7433 var r = rs.records[i];
7437 if(errors.length < 1){
7441 success : rs.success,
7447 ret = Roo.decode(response.responseText);
7451 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7461 Roo.form.Action.Load = function(form, options){
7462 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7463 this.reader = this.form.reader;
7466 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7471 Roo.Ajax.request(Roo.apply(
7472 this.createCallback(), {
7473 method:this.getMethod(),
7474 url:this.getUrl(false),
7475 params:this.getParams()
7479 success : function(response){
7481 var result = this.processResponse(response);
7482 if(result === true || !result.success || !result.data){
7483 this.failureType = Roo.form.Action.LOAD_FAILURE;
7484 this.form.afterAction(this, false);
7487 this.form.clearInvalid();
7488 this.form.setValues(result.data);
7489 this.form.afterAction(this, true);
7492 handleResponse : function(response){
7493 if(this.form.reader){
7494 var rs = this.form.reader.read(response);
7495 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7497 success : rs.success,
7501 return Roo.decode(response.responseText);
7505 Roo.form.Action.ACTION_TYPES = {
7506 'load' : Roo.form.Action.Load,
7507 'submit' : Roo.form.Action.Submit
7516 * @class Roo.bootstrap.Form
7517 * @extends Roo.bootstrap.Component
7518 * Bootstrap Form class
7519 * @cfg {String} method GET | POST (default POST)
7520 * @cfg {String} labelAlign top | left (default top)
7521 * @cfg {String} align left | right - for navbars
7522 * @cfg {Boolean} loadMask load mask when submit (default true)
7527 * @param {Object} config The config object
7531 Roo.bootstrap.Form = function(config){
7532 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7534 Roo.bootstrap.Form.popover.apply();
7538 * @event clientvalidation
7539 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7540 * @param {Form} this
7541 * @param {Boolean} valid true if the form has passed client-side validation
7543 clientvalidation: true,
7545 * @event beforeaction
7546 * Fires before any action is performed. Return false to cancel the action.
7547 * @param {Form} this
7548 * @param {Action} action The action to be performed
7552 * @event actionfailed
7553 * Fires when an action fails.
7554 * @param {Form} this
7555 * @param {Action} action The action that failed
7557 actionfailed : true,
7559 * @event actioncomplete
7560 * Fires when an action is completed.
7561 * @param {Form} this
7562 * @param {Action} action The action that completed
7564 actioncomplete : true
7569 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7572 * @cfg {String} method
7573 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7578 * The URL to use for form actions if one isn't supplied in the action options.
7581 * @cfg {Boolean} fileUpload
7582 * Set to true if this form is a file upload.
7586 * @cfg {Object} baseParams
7587 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7591 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7595 * @cfg {Sting} align (left|right) for navbar forms
7600 activeAction : null,
7603 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7604 * element by passing it or its id or mask the form itself by passing in true.
7607 waitMsgTarget : false,
7612 * @cfg {Boolean} errorMask (true|false) default false
7617 * @cfg {Number} maskOffset Default 100
7621 getAutoCreate : function(){
7625 method : this.method || 'POST',
7626 id : this.id || Roo.id(),
7629 if (this.parent().xtype.match(/^Nav/)) {
7630 cfg.cls = 'navbar-form navbar-' + this.align;
7634 if (this.labelAlign == 'left' ) {
7635 cfg.cls += ' form-horizontal';
7641 initEvents : function()
7643 this.el.on('submit', this.onSubmit, this);
7644 // this was added as random key presses on the form where triggering form submit.
7645 this.el.on('keypress', function(e) {
7646 if (e.getCharCode() != 13) {
7649 // we might need to allow it for textareas.. and some other items.
7650 // check e.getTarget().
7652 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7656 Roo.log("keypress blocked");
7664 onSubmit : function(e){
7669 * Returns true if client-side validation on the form is successful.
7672 isValid : function(){
7673 var items = this.getItems();
7677 items.each(function(f){
7683 if(!target && f.el.isVisible(true)){
7689 if(this.errorMask && !valid){
7690 Roo.bootstrap.Form.popover.mask(this, target);
7697 * Returns true if any fields in this form have changed since their original load.
7700 isDirty : function(){
7702 var items = this.getItems();
7703 items.each(function(f){
7713 * Performs a predefined action (submit or load) or custom actions you define on this form.
7714 * @param {String} actionName The name of the action type
7715 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7716 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7717 * accept other config options):
7719 Property Type Description
7720 ---------------- --------------- ----------------------------------------------------------------------------------
7721 url String The url for the action (defaults to the form's url)
7722 method String The form method to use (defaults to the form's method, or POST if not defined)
7723 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7724 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7725 validate the form on the client (defaults to false)
7727 * @return {BasicForm} this
7729 doAction : function(action, options){
7730 if(typeof action == 'string'){
7731 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7733 if(this.fireEvent('beforeaction', this, action) !== false){
7734 this.beforeAction(action);
7735 action.run.defer(100, action);
7741 beforeAction : function(action){
7742 var o = action.options;
7745 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7747 // not really supported yet.. ??
7749 //if(this.waitMsgTarget === true){
7750 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7751 //}else if(this.waitMsgTarget){
7752 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7753 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7755 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7761 afterAction : function(action, success){
7762 this.activeAction = null;
7763 var o = action.options;
7765 //if(this.waitMsgTarget === true){
7767 //}else if(this.waitMsgTarget){
7768 // this.waitMsgTarget.unmask();
7770 // Roo.MessageBox.updateProgress(1);
7771 // Roo.MessageBox.hide();
7778 Roo.callback(o.success, o.scope, [this, action]);
7779 this.fireEvent('actioncomplete', this, action);
7783 // failure condition..
7784 // we have a scenario where updates need confirming.
7785 // eg. if a locking scenario exists..
7786 // we look for { errors : { needs_confirm : true }} in the response.
7788 (typeof(action.result) != 'undefined') &&
7789 (typeof(action.result.errors) != 'undefined') &&
7790 (typeof(action.result.errors.needs_confirm) != 'undefined')
7793 Roo.log("not supported yet");
7796 Roo.MessageBox.confirm(
7797 "Change requires confirmation",
7798 action.result.errorMsg,
7803 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7813 Roo.callback(o.failure, o.scope, [this, action]);
7814 // show an error message if no failed handler is set..
7815 if (!this.hasListener('actionfailed')) {
7816 Roo.log("need to add dialog support");
7818 Roo.MessageBox.alert("Error",
7819 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7820 action.result.errorMsg :
7821 "Saving Failed, please check your entries or try again"
7826 this.fireEvent('actionfailed', this, action);
7831 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7832 * @param {String} id The value to search for
7835 findField : function(id){
7836 var items = this.getItems();
7837 var field = items.get(id);
7839 items.each(function(f){
7840 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7847 return field || null;
7850 * Mark fields in this form invalid in bulk.
7851 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7852 * @return {BasicForm} this
7854 markInvalid : function(errors){
7855 if(errors instanceof Array){
7856 for(var i = 0, len = errors.length; i < len; i++){
7857 var fieldError = errors[i];
7858 var f = this.findField(fieldError.id);
7860 f.markInvalid(fieldError.msg);
7866 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7867 field.markInvalid(errors[id]);
7871 //Roo.each(this.childForms || [], function (f) {
7872 // f.markInvalid(errors);
7879 * Set values for fields in this form in bulk.
7880 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7881 * @return {BasicForm} this
7883 setValues : function(values){
7884 if(values instanceof Array){ // array of objects
7885 for(var i = 0, len = values.length; i < len; i++){
7887 var f = this.findField(v.id);
7889 f.setValue(v.value);
7890 if(this.trackResetOnLoad){
7891 f.originalValue = f.getValue();
7895 }else{ // object hash
7898 if(typeof values[id] != 'function' && (field = this.findField(id))){
7900 if (field.setFromData &&
7902 field.displayField &&
7903 // combos' with local stores can
7904 // be queried via setValue()
7905 // to set their value..
7906 (field.store && !field.store.isLocal)
7910 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7911 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7912 field.setFromData(sd);
7914 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
7916 field.setFromData(values);
7919 field.setValue(values[id]);
7923 if(this.trackResetOnLoad){
7924 field.originalValue = field.getValue();
7930 //Roo.each(this.childForms || [], function (f) {
7931 // f.setValues(values);
7938 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7939 * they are returned as an array.
7940 * @param {Boolean} asString
7943 getValues : function(asString){
7944 //if (this.childForms) {
7945 // copy values from the child forms
7946 // Roo.each(this.childForms, function (f) {
7947 // this.setValues(f.getValues());
7953 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7954 if(asString === true){
7957 return Roo.urlDecode(fs);
7961 * Returns the fields in this form as an object with key/value pairs.
7962 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7965 getFieldValues : function(with_hidden)
7967 var items = this.getItems();
7969 items.each(function(f){
7975 var v = f.getValue();
7977 if (f.inputType =='radio') {
7978 if (typeof(ret[f.getName()]) == 'undefined') {
7979 ret[f.getName()] = ''; // empty..
7982 if (!f.el.dom.checked) {
7990 if(f.xtype == 'MoneyField'){
7991 ret[f.currencyName] = f.getCurrency();
7994 // not sure if this supported any more..
7995 if ((typeof(v) == 'object') && f.getRawValue) {
7996 v = f.getRawValue() ; // dates..
7998 // combo boxes where name != hiddenName...
7999 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8000 ret[f.name] = f.getRawValue();
8002 ret[f.getName()] = v;
8009 * Clears all invalid messages in this form.
8010 * @return {BasicForm} this
8012 clearInvalid : function(){
8013 var items = this.getItems();
8015 items.each(function(f){
8026 * @return {BasicForm} this
8029 var items = this.getItems();
8030 items.each(function(f){
8034 Roo.each(this.childForms || [], function (f) {
8041 getItems : function()
8043 var r=new Roo.util.MixedCollection(false, function(o){
8044 return o.id || (o.id = Roo.id());
8046 var iter = function(el) {
8053 Roo.each(el.items,function(e) {
8070 Roo.apply(Roo.bootstrap.Form, {
8097 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8098 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8099 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8100 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8103 this.maskEl.top.enableDisplayMode("block");
8104 this.maskEl.left.enableDisplayMode("block");
8105 this.maskEl.bottom.enableDisplayMode("block");
8106 this.maskEl.right.enableDisplayMode("block");
8108 this.toolTip = new Roo.bootstrap.Tooltip({
8109 cls : 'roo-form-error-popover',
8111 'left' : ['r-l', [-2,0], 'right'],
8112 'right' : ['l-r', [2,0], 'left'],
8113 'bottom' : ['tl-bl', [0,2], 'top'],
8114 'top' : [ 'bl-tl', [0,-2], 'bottom']
8118 this.toolTip.render(Roo.get(document.body));
8120 this.toolTip.el.enableDisplayMode("block");
8122 Roo.get(document.body).on('click', function(){
8126 Roo.get(document.body).on('touchstart', function(){
8130 this.isApplied = true
8133 mask : function(form, target)
8137 this.target = target;
8139 if(!this.form.errorMask || !target.el){
8143 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8145 Roo.log(scrollable);
8147 var ot = this.target.el.calcOffsetsTo(scrollable);
8149 var scrollTo = ot[1] - this.form.maskOffset;
8151 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8153 scrollable.scrollTo('top', scrollTo);
8155 var box = this.target.el.getBox();
8157 var zIndex = Roo.bootstrap.Modal.zIndex++;
8160 this.maskEl.top.setStyle('position', 'absolute');
8161 this.maskEl.top.setStyle('z-index', zIndex);
8162 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8163 this.maskEl.top.setLeft(0);
8164 this.maskEl.top.setTop(0);
8165 this.maskEl.top.show();
8167 this.maskEl.left.setStyle('position', 'absolute');
8168 this.maskEl.left.setStyle('z-index', zIndex);
8169 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8170 this.maskEl.left.setLeft(0);
8171 this.maskEl.left.setTop(box.y - this.padding);
8172 this.maskEl.left.show();
8174 this.maskEl.bottom.setStyle('position', 'absolute');
8175 this.maskEl.bottom.setStyle('z-index', zIndex);
8176 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8177 this.maskEl.bottom.setLeft(0);
8178 this.maskEl.bottom.setTop(box.bottom + this.padding);
8179 this.maskEl.bottom.show();
8181 this.maskEl.right.setStyle('position', 'absolute');
8182 this.maskEl.right.setStyle('z-index', zIndex);
8183 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8184 this.maskEl.right.setLeft(box.right + this.padding);
8185 this.maskEl.right.setTop(box.y - this.padding);
8186 this.maskEl.right.show();
8188 this.toolTip.bindEl = this.target.el;
8190 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8192 var tip = this.target.blankText;
8194 if(this.target.getValue() !== '' ) {
8196 if (this.target.invalidText.length) {
8197 tip = this.target.invalidText;
8198 } else if (this.target.regexText.length){
8199 tip = this.target.regexText;
8203 this.toolTip.show(tip);
8205 this.intervalID = window.setInterval(function() {
8206 Roo.bootstrap.Form.popover.unmask();
8209 window.onwheel = function(){ return false;};
8211 (function(){ this.isMasked = true; }).defer(500, this);
8217 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8221 this.maskEl.top.setStyle('position', 'absolute');
8222 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8223 this.maskEl.top.hide();
8225 this.maskEl.left.setStyle('position', 'absolute');
8226 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8227 this.maskEl.left.hide();
8229 this.maskEl.bottom.setStyle('position', 'absolute');
8230 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8231 this.maskEl.bottom.hide();
8233 this.maskEl.right.setStyle('position', 'absolute');
8234 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8235 this.maskEl.right.hide();
8237 this.toolTip.hide();
8239 this.toolTip.el.hide();
8241 window.onwheel = function(){ return true;};
8243 if(this.intervalID){
8244 window.clearInterval(this.intervalID);
8245 this.intervalID = false;
8248 this.isMasked = false;
8258 * Ext JS Library 1.1.1
8259 * Copyright(c) 2006-2007, Ext JS, LLC.
8261 * Originally Released Under LGPL - original licence link has changed is not relivant.
8264 * <script type="text/javascript">
8267 * @class Roo.form.VTypes
8268 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8271 Roo.form.VTypes = function(){
8272 // closure these in so they are only created once.
8273 var alpha = /^[a-zA-Z_]+$/;
8274 var alphanum = /^[a-zA-Z0-9_]+$/;
8275 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8276 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8278 // All these messages and functions are configurable
8281 * The function used to validate email addresses
8282 * @param {String} value The email address
8284 'email' : function(v){
8285 return email.test(v);
8288 * The error text to display when the email validation function returns false
8291 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8293 * The keystroke filter mask to be applied on email input
8296 'emailMask' : /[a-z0-9_\.\-@]/i,
8299 * The function used to validate URLs
8300 * @param {String} value The URL
8302 'url' : function(v){
8306 * The error text to display when the url validation function returns false
8309 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8312 * The function used to validate alpha values
8313 * @param {String} value The value
8315 'alpha' : function(v){
8316 return alpha.test(v);
8319 * The error text to display when the alpha validation function returns false
8322 'alphaText' : 'This field should only contain letters and _',
8324 * The keystroke filter mask to be applied on alpha input
8327 'alphaMask' : /[a-z_]/i,
8330 * The function used to validate alphanumeric values
8331 * @param {String} value The value
8333 'alphanum' : function(v){
8334 return alphanum.test(v);
8337 * The error text to display when the alphanumeric validation function returns false
8340 'alphanumText' : 'This field should only contain letters, numbers and _',
8342 * The keystroke filter mask to be applied on alphanumeric input
8345 'alphanumMask' : /[a-z0-9_]/i
8355 * @class Roo.bootstrap.Input
8356 * @extends Roo.bootstrap.Component
8357 * Bootstrap Input class
8358 * @cfg {Boolean} disabled is it disabled
8359 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8360 * @cfg {String} name name of the input
8361 * @cfg {string} fieldLabel - the label associated
8362 * @cfg {string} placeholder - placeholder to put in text.
8363 * @cfg {string} before - input group add on before
8364 * @cfg {string} after - input group add on after
8365 * @cfg {string} size - (lg|sm) or leave empty..
8366 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8367 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8368 * @cfg {Number} md colspan out of 12 for computer-sized screens
8369 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8370 * @cfg {string} value default value of the input
8371 * @cfg {Number} labelWidth set the width of label
8372 * @cfg {Number} labellg set the width of label (1-12)
8373 * @cfg {Number} labelmd set the width of label (1-12)
8374 * @cfg {Number} labelsm set the width of label (1-12)
8375 * @cfg {Number} labelxs set the width of label (1-12)
8376 * @cfg {String} labelAlign (top|left)
8377 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8378 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8379 * @cfg {String} indicatorpos (left|right) default left
8381 * @cfg {String} align (left|center|right) Default left
8382 * @cfg {Boolean} forceFeedback (true|false) Default false
8388 * Create a new Input
8389 * @param {Object} config The config object
8392 Roo.bootstrap.Input = function(config){
8394 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8399 * Fires when this field receives input focus.
8400 * @param {Roo.form.Field} this
8405 * Fires when this field loses input focus.
8406 * @param {Roo.form.Field} this
8411 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8412 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8413 * @param {Roo.form.Field} this
8414 * @param {Roo.EventObject} e The event object
8419 * Fires just before the field blurs if the field value has changed.
8420 * @param {Roo.form.Field} this
8421 * @param {Mixed} newValue The new value
8422 * @param {Mixed} oldValue The original value
8427 * Fires after the field has been marked as invalid.
8428 * @param {Roo.form.Field} this
8429 * @param {String} msg The validation message
8434 * Fires after the field has been validated with no errors.
8435 * @param {Roo.form.Field} this
8440 * Fires after the key up
8441 * @param {Roo.form.Field} this
8442 * @param {Roo.EventObject} e The event Object
8448 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8450 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8451 automatic validation (defaults to "keyup").
8453 validationEvent : "keyup",
8455 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8457 validateOnBlur : true,
8459 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8461 validationDelay : 250,
8463 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8465 focusClass : "x-form-focus", // not needed???
8469 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8471 invalidClass : "has-warning",
8474 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8476 validClass : "has-success",
8479 * @cfg {Boolean} hasFeedback (true|false) default true
8484 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8486 invalidFeedbackClass : "glyphicon-warning-sign",
8489 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8491 validFeedbackClass : "glyphicon-ok",
8494 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8496 selectOnFocus : false,
8499 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8503 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8508 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8510 disableKeyFilter : false,
8513 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8517 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8521 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8523 blankText : "Please complete this mandatory field",
8526 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8530 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8532 maxLength : Number.MAX_VALUE,
8534 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8536 minLengthText : "The minimum length for this field is {0}",
8538 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8540 maxLengthText : "The maximum length for this field is {0}",
8544 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8545 * If available, this function will be called only after the basic validators all return true, and will be passed the
8546 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8550 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8551 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8552 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8556 * @cfg {String} regexText -- Depricated - use Invalid Text
8561 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8567 autocomplete: false,
8586 formatedValue : false,
8587 forceFeedback : false,
8589 indicatorpos : 'left',
8596 parentLabelAlign : function()
8599 while (parent.parent()) {
8600 parent = parent.parent();
8601 if (typeof(parent.labelAlign) !='undefined') {
8602 return parent.labelAlign;
8609 getAutoCreate : function()
8611 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8617 if(this.inputType != 'hidden'){
8618 cfg.cls = 'form-group' //input-group
8624 type : this.inputType,
8626 cls : 'form-control',
8627 placeholder : this.placeholder || '',
8628 autocomplete : this.autocomplete || 'new-password'
8632 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8635 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8636 input.maxLength = this.maxLength;
8639 if (this.disabled) {
8640 input.disabled=true;
8643 if (this.readOnly) {
8644 input.readonly=true;
8648 input.name = this.name;
8652 input.cls += ' input-' + this.size;
8656 ['xs','sm','md','lg'].map(function(size){
8657 if (settings[size]) {
8658 cfg.cls += ' col-' + size + '-' + settings[size];
8662 var inputblock = input;
8666 cls: 'glyphicon form-control-feedback'
8669 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8672 cls : 'has-feedback',
8680 if (this.before || this.after) {
8683 cls : 'input-group',
8687 if (this.before && typeof(this.before) == 'string') {
8689 inputblock.cn.push({
8691 cls : 'roo-input-before input-group-addon',
8695 if (this.before && typeof(this.before) == 'object') {
8696 this.before = Roo.factory(this.before);
8698 inputblock.cn.push({
8700 cls : 'roo-input-before input-group-' +
8701 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8705 inputblock.cn.push(input);
8707 if (this.after && typeof(this.after) == 'string') {
8708 inputblock.cn.push({
8710 cls : 'roo-input-after input-group-addon',
8714 if (this.after && typeof(this.after) == 'object') {
8715 this.after = Roo.factory(this.after);
8717 inputblock.cn.push({
8719 cls : 'roo-input-after input-group-' +
8720 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8724 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8725 inputblock.cls += ' has-feedback';
8726 inputblock.cn.push(feedback);
8730 if (align ==='left' && this.fieldLabel.length) {
8732 cfg.cls += ' roo-form-group-label-left';
8737 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8738 tooltip : 'This field is required'
8743 cls : 'control-label',
8744 html : this.fieldLabel
8755 var labelCfg = cfg.cn[1];
8756 var contentCfg = cfg.cn[2];
8758 if(this.indicatorpos == 'right'){
8763 cls : 'control-label',
8767 html : this.fieldLabel
8771 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8772 tooltip : 'This field is required'
8785 labelCfg = cfg.cn[0];
8786 contentCfg = cfg.cn[1];
8790 if(this.labelWidth > 12){
8791 labelCfg.style = "width: " + this.labelWidth + 'px';
8794 if(this.labelWidth < 13 && this.labelmd == 0){
8795 this.labelmd = this.labelWidth;
8798 if(this.labellg > 0){
8799 labelCfg.cls += ' col-lg-' + this.labellg;
8800 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8803 if(this.labelmd > 0){
8804 labelCfg.cls += ' col-md-' + this.labelmd;
8805 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8808 if(this.labelsm > 0){
8809 labelCfg.cls += ' col-sm-' + this.labelsm;
8810 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8813 if(this.labelxs > 0){
8814 labelCfg.cls += ' col-xs-' + this.labelxs;
8815 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8819 } else if ( this.fieldLabel.length) {
8824 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8825 tooltip : 'This field is required'
8829 //cls : 'input-group-addon',
8830 html : this.fieldLabel
8838 if(this.indicatorpos == 'right'){
8843 //cls : 'input-group-addon',
8844 html : this.fieldLabel
8849 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8850 tooltip : 'This field is required'
8870 if (this.parentType === 'Navbar' && this.parent().bar) {
8871 cfg.cls += ' navbar-form';
8874 if (this.parentType === 'NavGroup') {
8875 cfg.cls += ' navbar-form';
8883 * return the real input element.
8885 inputEl: function ()
8887 return this.el.select('input.form-control',true).first();
8890 tooltipEl : function()
8892 return this.inputEl();
8895 indicatorEl : function()
8897 var indicator = this.el.select('i.roo-required-indicator',true).first();
8907 setDisabled : function(v)
8909 var i = this.inputEl().dom;
8911 i.removeAttribute('disabled');
8915 i.setAttribute('disabled','true');
8917 initEvents : function()
8920 this.inputEl().on("keydown" , this.fireKey, this);
8921 this.inputEl().on("focus", this.onFocus, this);
8922 this.inputEl().on("blur", this.onBlur, this);
8924 this.inputEl().relayEvent('keyup', this);
8926 this.indicator = this.indicatorEl();
8929 this.indicator.addClass('invisible');
8933 // reference to original value for reset
8934 this.originalValue = this.getValue();
8935 //Roo.form.TextField.superclass.initEvents.call(this);
8936 if(this.validationEvent == 'keyup'){
8937 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8938 this.inputEl().on('keyup', this.filterValidation, this);
8940 else if(this.validationEvent !== false){
8941 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8944 if(this.selectOnFocus){
8945 this.on("focus", this.preFocus, this);
8948 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8949 this.inputEl().on("keypress", this.filterKeys, this);
8951 this.inputEl().relayEvent('keypress', this);
8954 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8955 this.el.on("click", this.autoSize, this);
8958 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8959 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8962 if (typeof(this.before) == 'object') {
8963 this.before.render(this.el.select('.roo-input-before',true).first());
8965 if (typeof(this.after) == 'object') {
8966 this.after.render(this.el.select('.roo-input-after',true).first());
8971 filterValidation : function(e){
8972 if(!e.isNavKeyPress()){
8973 this.validationTask.delay(this.validationDelay);
8977 * Validates the field value
8978 * @return {Boolean} True if the value is valid, else false
8980 validate : function(){
8981 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8982 if(this.disabled || this.validateValue(this.getRawValue())){
8993 * Validates a value according to the field's validation rules and marks the field as invalid
8994 * if the validation fails
8995 * @param {Mixed} value The value to validate
8996 * @return {Boolean} True if the value is valid, else false
8998 validateValue : function(value){
8999 if(value.length < 1) { // if it's blank
9000 if(this.allowBlank){
9003 return this.inputEl().hasClass('hide') ? true : false;
9006 if(value.length < this.minLength){
9009 if(value.length > this.maxLength){
9013 var vt = Roo.form.VTypes;
9014 if(!vt[this.vtype](value, this)){
9018 if(typeof this.validator == "function"){
9019 var msg = this.validator(value);
9023 if (typeof(msg) == 'string') {
9024 this.invalidText = msg;
9028 if(this.regex && !this.regex.test(value)){
9038 fireKey : function(e){
9039 //Roo.log('field ' + e.getKey());
9040 if(e.isNavKeyPress()){
9041 this.fireEvent("specialkey", this, e);
9044 focus : function (selectText){
9046 this.inputEl().focus();
9047 if(selectText === true){
9048 this.inputEl().dom.select();
9054 onFocus : function(){
9055 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9056 // this.el.addClass(this.focusClass);
9059 this.hasFocus = true;
9060 this.startValue = this.getValue();
9061 this.fireEvent("focus", this);
9065 beforeBlur : Roo.emptyFn,
9069 onBlur : function(){
9071 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9072 //this.el.removeClass(this.focusClass);
9074 this.hasFocus = false;
9075 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9078 var v = this.getValue();
9079 if(String(v) !== String(this.startValue)){
9080 this.fireEvent('change', this, v, this.startValue);
9082 this.fireEvent("blur", this);
9086 * Resets the current field value to the originally loaded value and clears any validation messages
9089 this.setValue(this.originalValue);
9093 * Returns the name of the field
9094 * @return {Mixed} name The name field
9096 getName: function(){
9100 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9101 * @return {Mixed} value The field value
9103 getValue : function(){
9105 var v = this.inputEl().getValue();
9110 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9111 * @return {Mixed} value The field value
9113 getRawValue : function(){
9114 var v = this.inputEl().getValue();
9120 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9121 * @param {Mixed} value The value to set
9123 setRawValue : function(v){
9124 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9127 selectText : function(start, end){
9128 var v = this.getRawValue();
9130 start = start === undefined ? 0 : start;
9131 end = end === undefined ? v.length : end;
9132 var d = this.inputEl().dom;
9133 if(d.setSelectionRange){
9134 d.setSelectionRange(start, end);
9135 }else if(d.createTextRange){
9136 var range = d.createTextRange();
9137 range.moveStart("character", start);
9138 range.moveEnd("character", v.length-end);
9145 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9146 * @param {Mixed} value The value to set
9148 setValue : function(v){
9151 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9157 processValue : function(value){
9158 if(this.stripCharsRe){
9159 var newValue = value.replace(this.stripCharsRe, '');
9160 if(newValue !== value){
9161 this.setRawValue(newValue);
9168 preFocus : function(){
9170 if(this.selectOnFocus){
9171 this.inputEl().dom.select();
9174 filterKeys : function(e){
9176 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9179 var c = e.getCharCode(), cc = String.fromCharCode(c);
9180 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9183 if(!this.maskRe.test(cc)){
9188 * Clear any invalid styles/messages for this field
9190 clearInvalid : function(){
9192 if(!this.el || this.preventMark){ // not rendered
9197 this.el.removeClass(this.invalidClass);
9199 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9201 var feedback = this.el.select('.form-control-feedback', true).first();
9204 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9209 this.fireEvent('valid', this);
9213 * Mark this field as valid
9215 markValid : function()
9217 if(!this.el || this.preventMark){ // not rendered...
9221 this.el.removeClass([this.invalidClass, this.validClass]);
9223 var feedback = this.el.select('.form-control-feedback', true).first();
9226 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9233 if(this.allowBlank && !this.getRawValue().length){
9238 this.indicator.removeClass('visible');
9239 this.indicator.addClass('invisible');
9242 this.el.addClass(this.validClass);
9244 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9246 var feedback = this.el.select('.form-control-feedback', true).first();
9249 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9250 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9255 this.fireEvent('valid', this);
9259 * Mark this field as invalid
9260 * @param {String} msg The validation message
9262 markInvalid : function(msg)
9264 if(!this.el || this.preventMark){ // not rendered
9268 this.el.removeClass([this.invalidClass, this.validClass]);
9270 var feedback = this.el.select('.form-control-feedback', true).first();
9273 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9280 if(this.allowBlank && !this.getRawValue().length){
9285 this.indicator.removeClass('invisible');
9286 this.indicator.addClass('visible');
9289 this.el.addClass(this.invalidClass);
9291 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9293 var feedback = this.el.select('.form-control-feedback', true).first();
9296 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9298 if(this.getValue().length || this.forceFeedback){
9299 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9306 this.fireEvent('invalid', this, msg);
9309 SafariOnKeyDown : function(event)
9311 // this is a workaround for a password hang bug on chrome/ webkit.
9312 if (this.inputEl().dom.type != 'password') {
9316 var isSelectAll = false;
9318 if(this.inputEl().dom.selectionEnd > 0){
9319 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9321 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9322 event.preventDefault();
9327 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9329 event.preventDefault();
9330 // this is very hacky as keydown always get's upper case.
9332 var cc = String.fromCharCode(event.getCharCode());
9333 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9337 adjustWidth : function(tag, w){
9338 tag = tag.toLowerCase();
9339 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9340 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9344 if(tag == 'textarea'){
9347 }else if(Roo.isOpera){
9351 if(tag == 'textarea'){
9359 setFieldLabel : function(v)
9361 this.fieldLabel = v;
9364 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9378 * @class Roo.bootstrap.TextArea
9379 * @extends Roo.bootstrap.Input
9380 * Bootstrap TextArea class
9381 * @cfg {Number} cols Specifies the visible width of a text area
9382 * @cfg {Number} rows Specifies the visible number of lines in a text area
9383 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9384 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9385 * @cfg {string} html text
9388 * Create a new TextArea
9389 * @param {Object} config The config object
9392 Roo.bootstrap.TextArea = function(config){
9393 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9397 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9407 getAutoCreate : function(){
9409 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9415 if(this.inputType != 'hidden'){
9416 cfg.cls = 'form-group' //input-group
9424 value : this.value || '',
9425 html: this.html || '',
9426 cls : 'form-control',
9427 placeholder : this.placeholder || ''
9431 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9432 input.maxLength = this.maxLength;
9436 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9440 input.cols = this.cols;
9443 if (this.readOnly) {
9444 input.readonly = true;
9448 input.name = this.name;
9452 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9456 ['xs','sm','md','lg'].map(function(size){
9457 if (settings[size]) {
9458 cfg.cls += ' col-' + size + '-' + settings[size];
9462 var inputblock = input;
9464 if(this.hasFeedback && !this.allowBlank){
9468 cls: 'glyphicon form-control-feedback'
9472 cls : 'has-feedback',
9481 if (this.before || this.after) {
9484 cls : 'input-group',
9488 inputblock.cn.push({
9490 cls : 'input-group-addon',
9495 inputblock.cn.push(input);
9497 if(this.hasFeedback && !this.allowBlank){
9498 inputblock.cls += ' has-feedback';
9499 inputblock.cn.push(feedback);
9503 inputblock.cn.push({
9505 cls : 'input-group-addon',
9512 if (align ==='left' && this.fieldLabel.length) {
9517 cls : 'control-label',
9518 html : this.fieldLabel
9529 if(this.labelWidth > 12){
9530 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9533 if(this.labelWidth < 13 && this.labelmd == 0){
9534 this.labelmd = this.labelWidth;
9537 if(this.labellg > 0){
9538 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9539 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9542 if(this.labelmd > 0){
9543 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9544 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9547 if(this.labelsm > 0){
9548 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9549 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9552 if(this.labelxs > 0){
9553 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9554 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9557 } else if ( this.fieldLabel.length) {
9562 //cls : 'input-group-addon',
9563 html : this.fieldLabel
9581 if (this.disabled) {
9582 input.disabled=true;
9589 * return the real textarea element.
9591 inputEl: function ()
9593 return this.el.select('textarea.form-control',true).first();
9597 * Clear any invalid styles/messages for this field
9599 clearInvalid : function()
9602 if(!this.el || this.preventMark){ // not rendered
9606 var label = this.el.select('label', true).first();
9607 var icon = this.el.select('i.fa-star', true).first();
9613 this.el.removeClass(this.invalidClass);
9615 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9617 var feedback = this.el.select('.form-control-feedback', true).first();
9620 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9625 this.fireEvent('valid', this);
9629 * Mark this field as valid
9631 markValid : function()
9633 if(!this.el || this.preventMark){ // not rendered
9637 this.el.removeClass([this.invalidClass, this.validClass]);
9639 var feedback = this.el.select('.form-control-feedback', true).first();
9642 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9645 if(this.disabled || this.allowBlank){
9649 var label = this.el.select('label', true).first();
9650 var icon = this.el.select('i.fa-star', true).first();
9656 this.el.addClass(this.validClass);
9658 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9660 var feedback = this.el.select('.form-control-feedback', true).first();
9663 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9664 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9669 this.fireEvent('valid', this);
9673 * Mark this field as invalid
9674 * @param {String} msg The validation message
9676 markInvalid : function(msg)
9678 if(!this.el || this.preventMark){ // not rendered
9682 this.el.removeClass([this.invalidClass, this.validClass]);
9684 var feedback = this.el.select('.form-control-feedback', true).first();
9687 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9690 if(this.disabled || this.allowBlank){
9694 var label = this.el.select('label', true).first();
9695 var icon = this.el.select('i.fa-star', true).first();
9697 if(!this.getValue().length && label && !icon){
9698 this.el.createChild({
9700 cls : 'text-danger fa fa-lg fa-star',
9701 tooltip : 'This field is required',
9702 style : 'margin-right:5px;'
9706 this.el.addClass(this.invalidClass);
9708 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9710 var feedback = this.el.select('.form-control-feedback', true).first();
9713 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9715 if(this.getValue().length || this.forceFeedback){
9716 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9723 this.fireEvent('invalid', this, msg);
9731 * trigger field - base class for combo..
9736 * @class Roo.bootstrap.TriggerField
9737 * @extends Roo.bootstrap.Input
9738 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9739 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9740 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9741 * for which you can provide a custom implementation. For example:
9743 var trigger = new Roo.bootstrap.TriggerField();
9744 trigger.onTriggerClick = myTriggerFn;
9745 trigger.applyTo('my-field');
9748 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9749 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9750 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9751 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9752 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9755 * Create a new TriggerField.
9756 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9757 * to the base TextField)
9759 Roo.bootstrap.TriggerField = function(config){
9760 this.mimicing = false;
9761 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9764 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9766 * @cfg {String} triggerClass A CSS class to apply to the trigger
9769 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9774 * @cfg {Boolean} removable (true|false) special filter default false
9778 /** @cfg {Boolean} grow @hide */
9779 /** @cfg {Number} growMin @hide */
9780 /** @cfg {Number} growMax @hide */
9786 autoSize: Roo.emptyFn,
9793 actionMode : 'wrap',
9798 getAutoCreate : function(){
9800 var align = this.labelAlign || this.parentLabelAlign();
9805 cls: 'form-group' //input-group
9812 type : this.inputType,
9813 cls : 'form-control',
9814 autocomplete: 'new-password',
9815 placeholder : this.placeholder || ''
9819 input.name = this.name;
9822 input.cls += ' input-' + this.size;
9825 if (this.disabled) {
9826 input.disabled=true;
9829 var inputblock = input;
9831 if(this.hasFeedback && !this.allowBlank){
9835 cls: 'glyphicon form-control-feedback'
9838 if(this.removable && !this.editable && !this.tickable){
9840 cls : 'has-feedback',
9846 cls : 'roo-combo-removable-btn close'
9853 cls : 'has-feedback',
9862 if(this.removable && !this.editable && !this.tickable){
9864 cls : 'roo-removable',
9870 cls : 'roo-combo-removable-btn close'
9877 if (this.before || this.after) {
9880 cls : 'input-group',
9884 inputblock.cn.push({
9886 cls : 'input-group-addon',
9891 inputblock.cn.push(input);
9893 if(this.hasFeedback && !this.allowBlank){
9894 inputblock.cls += ' has-feedback';
9895 inputblock.cn.push(feedback);
9899 inputblock.cn.push({
9901 cls : 'input-group-addon',
9914 cls: 'form-hidden-field'
9928 cls: 'form-hidden-field'
9932 cls: 'roo-select2-choices',
9936 cls: 'roo-select2-search-field',
9949 cls: 'roo-select2-container input-group',
9954 // cls: 'typeahead typeahead-long dropdown-menu',
9955 // style: 'display:none'
9960 if(!this.multiple && this.showToggleBtn){
9966 if (this.caret != false) {
9969 cls: 'fa fa-' + this.caret
9976 cls : 'input-group-addon btn dropdown-toggle',
9981 cls: 'combobox-clear',
9995 combobox.cls += ' roo-select2-container-multi';
9998 if (align ==='left' && this.fieldLabel.length) {
10000 cfg.cls += ' roo-form-group-label-left';
10005 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10006 tooltip : 'This field is required'
10011 cls : 'control-label',
10012 html : this.fieldLabel
10024 var labelCfg = cfg.cn[1];
10025 var contentCfg = cfg.cn[2];
10027 if(this.indicatorpos == 'right'){
10032 cls : 'control-label',
10036 html : this.fieldLabel
10040 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10041 tooltip : 'This field is required'
10054 labelCfg = cfg.cn[0];
10055 contentCfg = cfg.cn[1];
10058 if(this.labelWidth > 12){
10059 labelCfg.style = "width: " + this.labelWidth + 'px';
10062 if(this.labelWidth < 13 && this.labelmd == 0){
10063 this.labelmd = this.labelWidth;
10066 if(this.labellg > 0){
10067 labelCfg.cls += ' col-lg-' + this.labellg;
10068 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10071 if(this.labelmd > 0){
10072 labelCfg.cls += ' col-md-' + this.labelmd;
10073 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10076 if(this.labelsm > 0){
10077 labelCfg.cls += ' col-sm-' + this.labelsm;
10078 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10081 if(this.labelxs > 0){
10082 labelCfg.cls += ' col-xs-' + this.labelxs;
10083 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10086 } else if ( this.fieldLabel.length) {
10087 // Roo.log(" label");
10091 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10092 tooltip : 'This field is required'
10096 //cls : 'input-group-addon',
10097 html : this.fieldLabel
10105 if(this.indicatorpos == 'right'){
10113 html : this.fieldLabel
10117 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10118 tooltip : 'This field is required'
10131 // Roo.log(" no label && no align");
10138 ['xs','sm','md','lg'].map(function(size){
10139 if (settings[size]) {
10140 cfg.cls += ' col-' + size + '-' + settings[size];
10151 onResize : function(w, h){
10152 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10153 // if(typeof w == 'number'){
10154 // var x = w - this.trigger.getWidth();
10155 // this.inputEl().setWidth(this.adjustWidth('input', x));
10156 // this.trigger.setStyle('left', x+'px');
10161 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10164 getResizeEl : function(){
10165 return this.inputEl();
10169 getPositionEl : function(){
10170 return this.inputEl();
10174 alignErrorIcon : function(){
10175 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10179 initEvents : function(){
10183 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10184 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10185 if(!this.multiple && this.showToggleBtn){
10186 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10187 if(this.hideTrigger){
10188 this.trigger.setDisplayed(false);
10190 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10194 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10197 if(this.removable && !this.editable && !this.tickable){
10198 var close = this.closeTriggerEl();
10201 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10202 close.on('click', this.removeBtnClick, this, close);
10206 //this.trigger.addClassOnOver('x-form-trigger-over');
10207 //this.trigger.addClassOnClick('x-form-trigger-click');
10210 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10214 closeTriggerEl : function()
10216 var close = this.el.select('.roo-combo-removable-btn', true).first();
10217 return close ? close : false;
10220 removeBtnClick : function(e, h, el)
10222 e.preventDefault();
10224 if(this.fireEvent("remove", this) !== false){
10226 this.fireEvent("afterremove", this)
10230 createList : function()
10232 this.list = Roo.get(document.body).createChild({
10234 cls: 'typeahead typeahead-long dropdown-menu',
10235 style: 'display:none'
10238 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10243 initTrigger : function(){
10248 onDestroy : function(){
10250 this.trigger.removeAllListeners();
10251 // this.trigger.remove();
10254 // this.wrap.remove();
10256 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10260 onFocus : function(){
10261 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10263 if(!this.mimicing){
10264 this.wrap.addClass('x-trigger-wrap-focus');
10265 this.mimicing = true;
10266 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10267 if(this.monitorTab){
10268 this.el.on("keydown", this.checkTab, this);
10275 checkTab : function(e){
10276 if(e.getKey() == e.TAB){
10277 this.triggerBlur();
10282 onBlur : function(){
10287 mimicBlur : function(e, t){
10289 if(!this.wrap.contains(t) && this.validateBlur()){
10290 this.triggerBlur();
10296 triggerBlur : function(){
10297 this.mimicing = false;
10298 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10299 if(this.monitorTab){
10300 this.el.un("keydown", this.checkTab, this);
10302 //this.wrap.removeClass('x-trigger-wrap-focus');
10303 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10307 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10308 validateBlur : function(e, t){
10313 onDisable : function(){
10314 this.inputEl().dom.disabled = true;
10315 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10317 // this.wrap.addClass('x-item-disabled');
10322 onEnable : function(){
10323 this.inputEl().dom.disabled = false;
10324 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10326 // this.el.removeClass('x-item-disabled');
10331 onShow : function(){
10332 var ae = this.getActionEl();
10335 ae.dom.style.display = '';
10336 ae.dom.style.visibility = 'visible';
10342 onHide : function(){
10343 var ae = this.getActionEl();
10344 ae.dom.style.display = 'none';
10348 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10349 * by an implementing function.
10351 * @param {EventObject} e
10353 onTriggerClick : Roo.emptyFn
10357 * Ext JS Library 1.1.1
10358 * Copyright(c) 2006-2007, Ext JS, LLC.
10360 * Originally Released Under LGPL - original licence link has changed is not relivant.
10363 * <script type="text/javascript">
10368 * @class Roo.data.SortTypes
10370 * Defines the default sorting (casting?) comparison functions used when sorting data.
10372 Roo.data.SortTypes = {
10374 * Default sort that does nothing
10375 * @param {Mixed} s The value being converted
10376 * @return {Mixed} The comparison value
10378 none : function(s){
10383 * The regular expression used to strip tags
10387 stripTagsRE : /<\/?[^>]+>/gi,
10390 * Strips all HTML tags to sort on text only
10391 * @param {Mixed} s The value being converted
10392 * @return {String} The comparison value
10394 asText : function(s){
10395 return String(s).replace(this.stripTagsRE, "");
10399 * Strips all HTML tags to sort on text only - Case insensitive
10400 * @param {Mixed} s The value being converted
10401 * @return {String} The comparison value
10403 asUCText : function(s){
10404 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10408 * Case insensitive string
10409 * @param {Mixed} s The value being converted
10410 * @return {String} The comparison value
10412 asUCString : function(s) {
10413 return String(s).toUpperCase();
10418 * @param {Mixed} s The value being converted
10419 * @return {Number} The comparison value
10421 asDate : function(s) {
10425 if(s instanceof Date){
10426 return s.getTime();
10428 return Date.parse(String(s));
10433 * @param {Mixed} s The value being converted
10434 * @return {Float} The comparison value
10436 asFloat : function(s) {
10437 var val = parseFloat(String(s).replace(/,/g, ""));
10446 * @param {Mixed} s The value being converted
10447 * @return {Number} The comparison value
10449 asInt : function(s) {
10450 var val = parseInt(String(s).replace(/,/g, ""));
10458 * Ext JS Library 1.1.1
10459 * Copyright(c) 2006-2007, Ext JS, LLC.
10461 * Originally Released Under LGPL - original licence link has changed is not relivant.
10464 * <script type="text/javascript">
10468 * @class Roo.data.Record
10469 * Instances of this class encapsulate both record <em>definition</em> information, and record
10470 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10471 * to access Records cached in an {@link Roo.data.Store} object.<br>
10473 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10474 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10477 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10479 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10480 * {@link #create}. The parameters are the same.
10481 * @param {Array} data An associative Array of data values keyed by the field name.
10482 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10483 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10484 * not specified an integer id is generated.
10486 Roo.data.Record = function(data, id){
10487 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10492 * Generate a constructor for a specific record layout.
10493 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10494 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10495 * Each field definition object may contain the following properties: <ul>
10496 * <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,
10497 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10498 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10499 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10500 * is being used, then this is a string containing the javascript expression to reference the data relative to
10501 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10502 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10503 * this may be omitted.</p></li>
10504 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10505 * <ul><li>auto (Default, implies no conversion)</li>
10510 * <li>date</li></ul></p></li>
10511 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10512 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10513 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10514 * by the Reader into an object that will be stored in the Record. It is passed the
10515 * following parameters:<ul>
10516 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10518 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10520 * <br>usage:<br><pre><code>
10521 var TopicRecord = Roo.data.Record.create(
10522 {name: 'title', mapping: 'topic_title'},
10523 {name: 'author', mapping: 'username'},
10524 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10525 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10526 {name: 'lastPoster', mapping: 'user2'},
10527 {name: 'excerpt', mapping: 'post_text'}
10530 var myNewRecord = new TopicRecord({
10531 title: 'Do my job please',
10534 lastPost: new Date(),
10535 lastPoster: 'Animal',
10536 excerpt: 'No way dude!'
10538 myStore.add(myNewRecord);
10543 Roo.data.Record.create = function(o){
10544 var f = function(){
10545 f.superclass.constructor.apply(this, arguments);
10547 Roo.extend(f, Roo.data.Record);
10548 var p = f.prototype;
10549 p.fields = new Roo.util.MixedCollection(false, function(field){
10552 for(var i = 0, len = o.length; i < len; i++){
10553 p.fields.add(new Roo.data.Field(o[i]));
10555 f.getField = function(name){
10556 return p.fields.get(name);
10561 Roo.data.Record.AUTO_ID = 1000;
10562 Roo.data.Record.EDIT = 'edit';
10563 Roo.data.Record.REJECT = 'reject';
10564 Roo.data.Record.COMMIT = 'commit';
10566 Roo.data.Record.prototype = {
10568 * Readonly flag - true if this record has been modified.
10577 join : function(store){
10578 this.store = store;
10582 * Set the named field to the specified value.
10583 * @param {String} name The name of the field to set.
10584 * @param {Object} value The value to set the field to.
10586 set : function(name, value){
10587 if(this.data[name] == value){
10591 if(!this.modified){
10592 this.modified = {};
10594 if(typeof this.modified[name] == 'undefined'){
10595 this.modified[name] = this.data[name];
10597 this.data[name] = value;
10598 if(!this.editing && this.store){
10599 this.store.afterEdit(this);
10604 * Get the value of the named field.
10605 * @param {String} name The name of the field to get the value of.
10606 * @return {Object} The value of the field.
10608 get : function(name){
10609 return this.data[name];
10613 beginEdit : function(){
10614 this.editing = true;
10615 this.modified = {};
10619 cancelEdit : function(){
10620 this.editing = false;
10621 delete this.modified;
10625 endEdit : function(){
10626 this.editing = false;
10627 if(this.dirty && this.store){
10628 this.store.afterEdit(this);
10633 * Usually called by the {@link Roo.data.Store} which owns the Record.
10634 * Rejects all changes made to the Record since either creation, or the last commit operation.
10635 * Modified fields are reverted to their original values.
10637 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10638 * of reject operations.
10640 reject : function(){
10641 var m = this.modified;
10643 if(typeof m[n] != "function"){
10644 this.data[n] = m[n];
10647 this.dirty = false;
10648 delete this.modified;
10649 this.editing = false;
10651 this.store.afterReject(this);
10656 * Usually called by the {@link Roo.data.Store} which owns the Record.
10657 * Commits all changes made to the Record since either creation, or the last commit operation.
10659 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10660 * of commit operations.
10662 commit : function(){
10663 this.dirty = false;
10664 delete this.modified;
10665 this.editing = false;
10667 this.store.afterCommit(this);
10672 hasError : function(){
10673 return this.error != null;
10677 clearError : function(){
10682 * Creates a copy of this record.
10683 * @param {String} id (optional) A new record id if you don't want to use this record's id
10686 copy : function(newId) {
10687 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10691 * Ext JS Library 1.1.1
10692 * Copyright(c) 2006-2007, Ext JS, LLC.
10694 * Originally Released Under LGPL - original licence link has changed is not relivant.
10697 * <script type="text/javascript">
10703 * @class Roo.data.Store
10704 * @extends Roo.util.Observable
10705 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10706 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10708 * 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
10709 * has no knowledge of the format of the data returned by the Proxy.<br>
10711 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10712 * instances from the data object. These records are cached and made available through accessor functions.
10714 * Creates a new Store.
10715 * @param {Object} config A config object containing the objects needed for the Store to access data,
10716 * and read the data into Records.
10718 Roo.data.Store = function(config){
10719 this.data = new Roo.util.MixedCollection(false);
10720 this.data.getKey = function(o){
10723 this.baseParams = {};
10725 this.paramNames = {
10730 "multisort" : "_multisort"
10733 if(config && config.data){
10734 this.inlineData = config.data;
10735 delete config.data;
10738 Roo.apply(this, config);
10740 if(this.reader){ // reader passed
10741 this.reader = Roo.factory(this.reader, Roo.data);
10742 this.reader.xmodule = this.xmodule || false;
10743 if(!this.recordType){
10744 this.recordType = this.reader.recordType;
10746 if(this.reader.onMetaChange){
10747 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10751 if(this.recordType){
10752 this.fields = this.recordType.prototype.fields;
10754 this.modified = [];
10758 * @event datachanged
10759 * Fires when the data cache has changed, and a widget which is using this Store
10760 * as a Record cache should refresh its view.
10761 * @param {Store} this
10763 datachanged : true,
10765 * @event metachange
10766 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10767 * @param {Store} this
10768 * @param {Object} meta The JSON metadata
10773 * Fires when Records have been added to the Store
10774 * @param {Store} this
10775 * @param {Roo.data.Record[]} records The array of Records added
10776 * @param {Number} index The index at which the record(s) were added
10781 * Fires when a Record has been removed from the Store
10782 * @param {Store} this
10783 * @param {Roo.data.Record} record The Record that was removed
10784 * @param {Number} index The index at which the record was removed
10789 * Fires when a Record has been updated
10790 * @param {Store} this
10791 * @param {Roo.data.Record} record The Record that was updated
10792 * @param {String} operation The update operation being performed. Value may be one of:
10794 Roo.data.Record.EDIT
10795 Roo.data.Record.REJECT
10796 Roo.data.Record.COMMIT
10802 * Fires when the data cache has been cleared.
10803 * @param {Store} this
10807 * @event beforeload
10808 * Fires before a request is made for a new data object. If the beforeload handler returns false
10809 * the load action will be canceled.
10810 * @param {Store} this
10811 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10815 * @event beforeloadadd
10816 * Fires after a new set of Records has been loaded.
10817 * @param {Store} this
10818 * @param {Roo.data.Record[]} records The Records that were loaded
10819 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10821 beforeloadadd : true,
10824 * Fires after a new set of Records has been loaded, before they are added to the store.
10825 * @param {Store} this
10826 * @param {Roo.data.Record[]} records The Records that were loaded
10827 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10828 * @params {Object} return from reader
10832 * @event loadexception
10833 * Fires if an exception occurs in the Proxy during loading.
10834 * Called with the signature of the Proxy's "loadexception" event.
10835 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10838 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10839 * @param {Object} load options
10840 * @param {Object} jsonData from your request (normally this contains the Exception)
10842 loadexception : true
10846 this.proxy = Roo.factory(this.proxy, Roo.data);
10847 this.proxy.xmodule = this.xmodule || false;
10848 this.relayEvents(this.proxy, ["loadexception"]);
10850 this.sortToggle = {};
10851 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10853 Roo.data.Store.superclass.constructor.call(this);
10855 if(this.inlineData){
10856 this.loadData(this.inlineData);
10857 delete this.inlineData;
10861 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10863 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10864 * without a remote query - used by combo/forms at present.
10868 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10871 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10874 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10875 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10878 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10879 * on any HTTP request
10882 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10885 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10889 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10890 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10892 remoteSort : false,
10895 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10896 * loaded or when a record is removed. (defaults to false).
10898 pruneModifiedRecords : false,
10901 lastOptions : null,
10904 * Add Records to the Store and fires the add event.
10905 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10907 add : function(records){
10908 records = [].concat(records);
10909 for(var i = 0, len = records.length; i < len; i++){
10910 records[i].join(this);
10912 var index = this.data.length;
10913 this.data.addAll(records);
10914 this.fireEvent("add", this, records, index);
10918 * Remove a Record from the Store and fires the remove event.
10919 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10921 remove : function(record){
10922 var index = this.data.indexOf(record);
10923 this.data.removeAt(index);
10924 if(this.pruneModifiedRecords){
10925 this.modified.remove(record);
10927 this.fireEvent("remove", this, record, index);
10931 * Remove all Records from the Store and fires the clear event.
10933 removeAll : function(){
10935 if(this.pruneModifiedRecords){
10936 this.modified = [];
10938 this.fireEvent("clear", this);
10942 * Inserts Records to the Store at the given index and fires the add event.
10943 * @param {Number} index The start index at which to insert the passed Records.
10944 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10946 insert : function(index, records){
10947 records = [].concat(records);
10948 for(var i = 0, len = records.length; i < len; i++){
10949 this.data.insert(index, records[i]);
10950 records[i].join(this);
10952 this.fireEvent("add", this, records, index);
10956 * Get the index within the cache of the passed Record.
10957 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10958 * @return {Number} The index of the passed Record. Returns -1 if not found.
10960 indexOf : function(record){
10961 return this.data.indexOf(record);
10965 * Get the index within the cache of the Record with the passed id.
10966 * @param {String} id The id of the Record to find.
10967 * @return {Number} The index of the Record. Returns -1 if not found.
10969 indexOfId : function(id){
10970 return this.data.indexOfKey(id);
10974 * Get the Record with the specified id.
10975 * @param {String} id The id of the Record to find.
10976 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10978 getById : function(id){
10979 return this.data.key(id);
10983 * Get the Record at the specified index.
10984 * @param {Number} index The index of the Record to find.
10985 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10987 getAt : function(index){
10988 return this.data.itemAt(index);
10992 * Returns a range of Records between specified indices.
10993 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10994 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10995 * @return {Roo.data.Record[]} An array of Records
10997 getRange : function(start, end){
10998 return this.data.getRange(start, end);
11002 storeOptions : function(o){
11003 o = Roo.apply({}, o);
11006 this.lastOptions = o;
11010 * Loads the Record cache from the configured Proxy using the configured Reader.
11012 * If using remote paging, then the first load call must specify the <em>start</em>
11013 * and <em>limit</em> properties in the options.params property to establish the initial
11014 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11016 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11017 * and this call will return before the new data has been loaded. Perform any post-processing
11018 * in a callback function, or in a "load" event handler.</strong>
11020 * @param {Object} options An object containing properties which control loading options:<ul>
11021 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11022 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11023 * passed the following arguments:<ul>
11024 * <li>r : Roo.data.Record[]</li>
11025 * <li>options: Options object from the load call</li>
11026 * <li>success: Boolean success indicator</li></ul></li>
11027 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11028 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11031 load : function(options){
11032 options = options || {};
11033 if(this.fireEvent("beforeload", this, options) !== false){
11034 this.storeOptions(options);
11035 var p = Roo.apply(options.params || {}, this.baseParams);
11036 // if meta was not loaded from remote source.. try requesting it.
11037 if (!this.reader.metaFromRemote) {
11038 p._requestMeta = 1;
11040 if(this.sortInfo && this.remoteSort){
11041 var pn = this.paramNames;
11042 p[pn["sort"]] = this.sortInfo.field;
11043 p[pn["dir"]] = this.sortInfo.direction;
11045 if (this.multiSort) {
11046 var pn = this.paramNames;
11047 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11050 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11055 * Reloads the Record cache from the configured Proxy using the configured Reader and
11056 * the options from the last load operation performed.
11057 * @param {Object} options (optional) An object containing properties which may override the options
11058 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11059 * the most recently used options are reused).
11061 reload : function(options){
11062 this.load(Roo.applyIf(options||{}, this.lastOptions));
11066 // Called as a callback by the Reader during a load operation.
11067 loadRecords : function(o, options, success){
11068 if(!o || success === false){
11069 if(success !== false){
11070 this.fireEvent("load", this, [], options, o);
11072 if(options.callback){
11073 options.callback.call(options.scope || this, [], options, false);
11077 // if data returned failure - throw an exception.
11078 if (o.success === false) {
11079 // show a message if no listener is registered.
11080 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11081 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11083 // loadmask wil be hooked into this..
11084 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11087 var r = o.records, t = o.totalRecords || r.length;
11089 this.fireEvent("beforeloadadd", this, r, options, o);
11091 if(!options || options.add !== true){
11092 if(this.pruneModifiedRecords){
11093 this.modified = [];
11095 for(var i = 0, len = r.length; i < len; i++){
11099 this.data = this.snapshot;
11100 delete this.snapshot;
11103 this.data.addAll(r);
11104 this.totalLength = t;
11106 this.fireEvent("datachanged", this);
11108 this.totalLength = Math.max(t, this.data.length+r.length);
11112 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11114 var e = new Roo.data.Record({});
11116 e.set(this.parent.displayField, this.parent.emptyTitle);
11117 e.set(this.parent.valueField, '');
11122 this.fireEvent("load", this, r, options, o);
11123 if(options.callback){
11124 options.callback.call(options.scope || this, r, options, true);
11130 * Loads data from a passed data block. A Reader which understands the format of the data
11131 * must have been configured in the constructor.
11132 * @param {Object} data The data block from which to read the Records. The format of the data expected
11133 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11134 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11136 loadData : function(o, append){
11137 var r = this.reader.readRecords(o);
11138 this.loadRecords(r, {add: append}, true);
11142 * Gets the number of cached records.
11144 * <em>If using paging, this may not be the total size of the dataset. If the data object
11145 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11146 * the data set size</em>
11148 getCount : function(){
11149 return this.data.length || 0;
11153 * Gets the total number of records in the dataset as returned by the server.
11155 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11156 * the dataset size</em>
11158 getTotalCount : function(){
11159 return this.totalLength || 0;
11163 * Returns the sort state of the Store as an object with two properties:
11165 field {String} The name of the field by which the Records are sorted
11166 direction {String} The sort order, "ASC" or "DESC"
11169 getSortState : function(){
11170 return this.sortInfo;
11174 applySort : function(){
11175 if(this.sortInfo && !this.remoteSort){
11176 var s = this.sortInfo, f = s.field;
11177 var st = this.fields.get(f).sortType;
11178 var fn = function(r1, r2){
11179 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11180 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11182 this.data.sort(s.direction, fn);
11183 if(this.snapshot && this.snapshot != this.data){
11184 this.snapshot.sort(s.direction, fn);
11190 * Sets the default sort column and order to be used by the next load operation.
11191 * @param {String} fieldName The name of the field to sort by.
11192 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11194 setDefaultSort : function(field, dir){
11195 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11199 * Sort the Records.
11200 * If remote sorting is used, the sort is performed on the server, and the cache is
11201 * reloaded. If local sorting is used, the cache is sorted internally.
11202 * @param {String} fieldName The name of the field to sort by.
11203 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11205 sort : function(fieldName, dir){
11206 var f = this.fields.get(fieldName);
11208 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11210 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11211 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11216 this.sortToggle[f.name] = dir;
11217 this.sortInfo = {field: f.name, direction: dir};
11218 if(!this.remoteSort){
11220 this.fireEvent("datachanged", this);
11222 this.load(this.lastOptions);
11227 * Calls the specified function for each of the Records in the cache.
11228 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11229 * Returning <em>false</em> aborts and exits the iteration.
11230 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11232 each : function(fn, scope){
11233 this.data.each(fn, scope);
11237 * Gets all records modified since the last commit. Modified records are persisted across load operations
11238 * (e.g., during paging).
11239 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11241 getModifiedRecords : function(){
11242 return this.modified;
11246 createFilterFn : function(property, value, anyMatch){
11247 if(!value.exec){ // not a regex
11248 value = String(value);
11249 if(value.length == 0){
11252 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11254 return function(r){
11255 return value.test(r.data[property]);
11260 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11261 * @param {String} property A field on your records
11262 * @param {Number} start The record index to start at (defaults to 0)
11263 * @param {Number} end The last record index to include (defaults to length - 1)
11264 * @return {Number} The sum
11266 sum : function(property, start, end){
11267 var rs = this.data.items, v = 0;
11268 start = start || 0;
11269 end = (end || end === 0) ? end : rs.length-1;
11271 for(var i = start; i <= end; i++){
11272 v += (rs[i].data[property] || 0);
11278 * Filter the records by a specified property.
11279 * @param {String} field A field on your records
11280 * @param {String/RegExp} value Either a string that the field
11281 * should start with or a RegExp to test against the field
11282 * @param {Boolean} anyMatch True to match any part not just the beginning
11284 filter : function(property, value, anyMatch){
11285 var fn = this.createFilterFn(property, value, anyMatch);
11286 return fn ? this.filterBy(fn) : this.clearFilter();
11290 * Filter by a function. The specified function will be called with each
11291 * record in this data source. If the function returns true the record is included,
11292 * otherwise it is filtered.
11293 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11294 * @param {Object} scope (optional) The scope of the function (defaults to this)
11296 filterBy : function(fn, scope){
11297 this.snapshot = this.snapshot || this.data;
11298 this.data = this.queryBy(fn, scope||this);
11299 this.fireEvent("datachanged", this);
11303 * Query the records by a specified property.
11304 * @param {String} field A field on your records
11305 * @param {String/RegExp} value Either a string that the field
11306 * should start with or a RegExp to test against the field
11307 * @param {Boolean} anyMatch True to match any part not just the beginning
11308 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11310 query : function(property, value, anyMatch){
11311 var fn = this.createFilterFn(property, value, anyMatch);
11312 return fn ? this.queryBy(fn) : this.data.clone();
11316 * Query by a function. The specified function will be called with each
11317 * record in this data source. If the function returns true the record is included
11319 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11320 * @param {Object} scope (optional) The scope of the function (defaults to this)
11321 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11323 queryBy : function(fn, scope){
11324 var data = this.snapshot || this.data;
11325 return data.filterBy(fn, scope||this);
11329 * Collects unique values for a particular dataIndex from this store.
11330 * @param {String} dataIndex The property to collect
11331 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11332 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11333 * @return {Array} An array of the unique values
11335 collect : function(dataIndex, allowNull, bypassFilter){
11336 var d = (bypassFilter === true && this.snapshot) ?
11337 this.snapshot.items : this.data.items;
11338 var v, sv, r = [], l = {};
11339 for(var i = 0, len = d.length; i < len; i++){
11340 v = d[i].data[dataIndex];
11342 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11351 * Revert to a view of the Record cache with no filtering applied.
11352 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11354 clearFilter : function(suppressEvent){
11355 if(this.snapshot && this.snapshot != this.data){
11356 this.data = this.snapshot;
11357 delete this.snapshot;
11358 if(suppressEvent !== true){
11359 this.fireEvent("datachanged", this);
11365 afterEdit : function(record){
11366 if(this.modified.indexOf(record) == -1){
11367 this.modified.push(record);
11369 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11373 afterReject : function(record){
11374 this.modified.remove(record);
11375 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11379 afterCommit : function(record){
11380 this.modified.remove(record);
11381 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11385 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11386 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11388 commitChanges : function(){
11389 var m = this.modified.slice(0);
11390 this.modified = [];
11391 for(var i = 0, len = m.length; i < len; i++){
11397 * Cancel outstanding changes on all changed records.
11399 rejectChanges : function(){
11400 var m = this.modified.slice(0);
11401 this.modified = [];
11402 for(var i = 0, len = m.length; i < len; i++){
11407 onMetaChange : function(meta, rtype, o){
11408 this.recordType = rtype;
11409 this.fields = rtype.prototype.fields;
11410 delete this.snapshot;
11411 this.sortInfo = meta.sortInfo || this.sortInfo;
11412 this.modified = [];
11413 this.fireEvent('metachange', this, this.reader.meta);
11416 moveIndex : function(data, type)
11418 var index = this.indexOf(data);
11420 var newIndex = index + type;
11424 this.insert(newIndex, data);
11429 * Ext JS Library 1.1.1
11430 * Copyright(c) 2006-2007, Ext JS, LLC.
11432 * Originally Released Under LGPL - original licence link has changed is not relivant.
11435 * <script type="text/javascript">
11439 * @class Roo.data.SimpleStore
11440 * @extends Roo.data.Store
11441 * Small helper class to make creating Stores from Array data easier.
11442 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11443 * @cfg {Array} fields An array of field definition objects, or field name strings.
11444 * @cfg {Array} data The multi-dimensional array of data
11446 * @param {Object} config
11448 Roo.data.SimpleStore = function(config){
11449 Roo.data.SimpleStore.superclass.constructor.call(this, {
11451 reader: new Roo.data.ArrayReader({
11454 Roo.data.Record.create(config.fields)
11456 proxy : new Roo.data.MemoryProxy(config.data)
11460 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11462 * Ext JS Library 1.1.1
11463 * Copyright(c) 2006-2007, Ext JS, LLC.
11465 * Originally Released Under LGPL - original licence link has changed is not relivant.
11468 * <script type="text/javascript">
11473 * @extends Roo.data.Store
11474 * @class Roo.data.JsonStore
11475 * Small helper class to make creating Stores for JSON data easier. <br/>
11477 var store = new Roo.data.JsonStore({
11478 url: 'get-images.php',
11480 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11483 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11484 * JsonReader and HttpProxy (unless inline data is provided).</b>
11485 * @cfg {Array} fields An array of field definition objects, or field name strings.
11487 * @param {Object} config
11489 Roo.data.JsonStore = function(c){
11490 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11491 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11492 reader: new Roo.data.JsonReader(c, c.fields)
11495 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11497 * Ext JS Library 1.1.1
11498 * Copyright(c) 2006-2007, Ext JS, LLC.
11500 * Originally Released Under LGPL - original licence link has changed is not relivant.
11503 * <script type="text/javascript">
11507 Roo.data.Field = function(config){
11508 if(typeof config == "string"){
11509 config = {name: config};
11511 Roo.apply(this, config);
11514 this.type = "auto";
11517 var st = Roo.data.SortTypes;
11518 // named sortTypes are supported, here we look them up
11519 if(typeof this.sortType == "string"){
11520 this.sortType = st[this.sortType];
11523 // set default sortType for strings and dates
11524 if(!this.sortType){
11527 this.sortType = st.asUCString;
11530 this.sortType = st.asDate;
11533 this.sortType = st.none;
11538 var stripRe = /[\$,%]/g;
11540 // prebuilt conversion function for this field, instead of
11541 // switching every time we're reading a value
11543 var cv, dateFormat = this.dateFormat;
11548 cv = function(v){ return v; };
11551 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11555 return v !== undefined && v !== null && v !== '' ?
11556 parseInt(String(v).replace(stripRe, ""), 10) : '';
11561 return v !== undefined && v !== null && v !== '' ?
11562 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11567 cv = function(v){ return v === true || v === "true" || v == 1; };
11574 if(v instanceof Date){
11578 if(dateFormat == "timestamp"){
11579 return new Date(v*1000);
11581 return Date.parseDate(v, dateFormat);
11583 var parsed = Date.parse(v);
11584 return parsed ? new Date(parsed) : null;
11593 Roo.data.Field.prototype = {
11601 * Ext JS Library 1.1.1
11602 * Copyright(c) 2006-2007, Ext JS, LLC.
11604 * Originally Released Under LGPL - original licence link has changed is not relivant.
11607 * <script type="text/javascript">
11610 // Base class for reading structured data from a data source. This class is intended to be
11611 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11614 * @class Roo.data.DataReader
11615 * Base class for reading structured data from a data source. This class is intended to be
11616 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11619 Roo.data.DataReader = function(meta, recordType){
11623 this.recordType = recordType instanceof Array ?
11624 Roo.data.Record.create(recordType) : recordType;
11627 Roo.data.DataReader.prototype = {
11629 * Create an empty record
11630 * @param {Object} data (optional) - overlay some values
11631 * @return {Roo.data.Record} record created.
11633 newRow : function(d) {
11635 this.recordType.prototype.fields.each(function(c) {
11637 case 'int' : da[c.name] = 0; break;
11638 case 'date' : da[c.name] = new Date(); break;
11639 case 'float' : da[c.name] = 0.0; break;
11640 case 'boolean' : da[c.name] = false; break;
11641 default : da[c.name] = ""; break;
11645 return new this.recordType(Roo.apply(da, d));
11650 * Ext JS Library 1.1.1
11651 * Copyright(c) 2006-2007, Ext JS, LLC.
11653 * Originally Released Under LGPL - original licence link has changed is not relivant.
11656 * <script type="text/javascript">
11660 * @class Roo.data.DataProxy
11661 * @extends Roo.data.Observable
11662 * This class is an abstract base class for implementations which provide retrieval of
11663 * unformatted data objects.<br>
11665 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11666 * (of the appropriate type which knows how to parse the data object) to provide a block of
11667 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11669 * Custom implementations must implement the load method as described in
11670 * {@link Roo.data.HttpProxy#load}.
11672 Roo.data.DataProxy = function(){
11675 * @event beforeload
11676 * Fires before a network request is made to retrieve a data object.
11677 * @param {Object} This DataProxy object.
11678 * @param {Object} params The params parameter to the load function.
11683 * Fires before the load method's callback is called.
11684 * @param {Object} This DataProxy object.
11685 * @param {Object} o The data object.
11686 * @param {Object} arg The callback argument object passed to the load function.
11690 * @event loadexception
11691 * Fires if an Exception occurs during data retrieval.
11692 * @param {Object} This DataProxy object.
11693 * @param {Object} o The data object.
11694 * @param {Object} arg The callback argument object passed to the load function.
11695 * @param {Object} e The Exception.
11697 loadexception : true
11699 Roo.data.DataProxy.superclass.constructor.call(this);
11702 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11705 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11709 * Ext JS Library 1.1.1
11710 * Copyright(c) 2006-2007, Ext JS, LLC.
11712 * Originally Released Under LGPL - original licence link has changed is not relivant.
11715 * <script type="text/javascript">
11718 * @class Roo.data.MemoryProxy
11719 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11720 * to the Reader when its load method is called.
11722 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11724 Roo.data.MemoryProxy = function(data){
11728 Roo.data.MemoryProxy.superclass.constructor.call(this);
11732 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11735 * Load data from the requested source (in this case an in-memory
11736 * data object passed to the constructor), read the data object into
11737 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11738 * process that block using the passed callback.
11739 * @param {Object} params This parameter is not used by the MemoryProxy class.
11740 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11741 * object into a block of Roo.data.Records.
11742 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11743 * The function must be passed <ul>
11744 * <li>The Record block object</li>
11745 * <li>The "arg" argument from the load function</li>
11746 * <li>A boolean success indicator</li>
11748 * @param {Object} scope The scope in which to call the callback
11749 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11751 load : function(params, reader, callback, scope, arg){
11752 params = params || {};
11755 result = reader.readRecords(this.data);
11757 this.fireEvent("loadexception", this, arg, null, e);
11758 callback.call(scope, null, arg, false);
11761 callback.call(scope, result, arg, true);
11765 update : function(params, records){
11770 * Ext JS Library 1.1.1
11771 * Copyright(c) 2006-2007, Ext JS, LLC.
11773 * Originally Released Under LGPL - original licence link has changed is not relivant.
11776 * <script type="text/javascript">
11779 * @class Roo.data.HttpProxy
11780 * @extends Roo.data.DataProxy
11781 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11782 * configured to reference a certain URL.<br><br>
11784 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11785 * from which the running page was served.<br><br>
11787 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11789 * Be aware that to enable the browser to parse an XML document, the server must set
11790 * the Content-Type header in the HTTP response to "text/xml".
11792 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11793 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11794 * will be used to make the request.
11796 Roo.data.HttpProxy = function(conn){
11797 Roo.data.HttpProxy.superclass.constructor.call(this);
11798 // is conn a conn config or a real conn?
11800 this.useAjax = !conn || !conn.events;
11804 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11805 // thse are take from connection...
11808 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11811 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11812 * extra parameters to each request made by this object. (defaults to undefined)
11815 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11816 * to each request made by this object. (defaults to undefined)
11819 * @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)
11822 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11825 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11831 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11835 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11836 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11837 * a finer-grained basis than the DataProxy events.
11839 getConnection : function(){
11840 return this.useAjax ? Roo.Ajax : this.conn;
11844 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11845 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11846 * process that block using the passed callback.
11847 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11848 * for the request to the remote server.
11849 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11850 * object into a block of Roo.data.Records.
11851 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11852 * The function must be passed <ul>
11853 * <li>The Record block object</li>
11854 * <li>The "arg" argument from the load function</li>
11855 * <li>A boolean success indicator</li>
11857 * @param {Object} scope The scope in which to call the callback
11858 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11860 load : function(params, reader, callback, scope, arg){
11861 if(this.fireEvent("beforeload", this, params) !== false){
11863 params : params || {},
11865 callback : callback,
11870 callback : this.loadResponse,
11874 Roo.applyIf(o, this.conn);
11875 if(this.activeRequest){
11876 Roo.Ajax.abort(this.activeRequest);
11878 this.activeRequest = Roo.Ajax.request(o);
11880 this.conn.request(o);
11883 callback.call(scope||this, null, arg, false);
11888 loadResponse : function(o, success, response){
11889 delete this.activeRequest;
11891 this.fireEvent("loadexception", this, o, response);
11892 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11897 result = o.reader.read(response);
11899 this.fireEvent("loadexception", this, o, response, e);
11900 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11904 this.fireEvent("load", this, o, o.request.arg);
11905 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11909 update : function(dataSet){
11914 updateResponse : function(dataSet){
11919 * Ext JS Library 1.1.1
11920 * Copyright(c) 2006-2007, Ext JS, LLC.
11922 * Originally Released Under LGPL - original licence link has changed is not relivant.
11925 * <script type="text/javascript">
11929 * @class Roo.data.ScriptTagProxy
11930 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11931 * other than the originating domain of the running page.<br><br>
11933 * <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
11934 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11936 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11937 * source code that is used as the source inside a <script> tag.<br><br>
11939 * In order for the browser to process the returned data, the server must wrap the data object
11940 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11941 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11942 * depending on whether the callback name was passed:
11945 boolean scriptTag = false;
11946 String cb = request.getParameter("callback");
11949 response.setContentType("text/javascript");
11951 response.setContentType("application/x-json");
11953 Writer out = response.getWriter();
11955 out.write(cb + "(");
11957 out.print(dataBlock.toJsonString());
11964 * @param {Object} config A configuration object.
11966 Roo.data.ScriptTagProxy = function(config){
11967 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11968 Roo.apply(this, config);
11969 this.head = document.getElementsByTagName("head")[0];
11972 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11974 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11976 * @cfg {String} url The URL from which to request the data object.
11979 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11983 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11984 * the server the name of the callback function set up by the load call to process the returned data object.
11985 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11986 * javascript output which calls this named function passing the data object as its only parameter.
11988 callbackParam : "callback",
11990 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11991 * name to the request.
11996 * Load data from the configured URL, read the data object into
11997 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11998 * process that block using the passed callback.
11999 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12000 * for the request to the remote server.
12001 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12002 * object into a block of Roo.data.Records.
12003 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12004 * The function must be passed <ul>
12005 * <li>The Record block object</li>
12006 * <li>The "arg" argument from the load function</li>
12007 * <li>A boolean success indicator</li>
12009 * @param {Object} scope The scope in which to call the callback
12010 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12012 load : function(params, reader, callback, scope, arg){
12013 if(this.fireEvent("beforeload", this, params) !== false){
12015 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12017 var url = this.url;
12018 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12020 url += "&_dc=" + (new Date().getTime());
12022 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12025 cb : "stcCallback"+transId,
12026 scriptId : "stcScript"+transId,
12030 callback : callback,
12036 window[trans.cb] = function(o){
12037 conn.handleResponse(o, trans);
12040 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12042 if(this.autoAbort !== false){
12046 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12048 var script = document.createElement("script");
12049 script.setAttribute("src", url);
12050 script.setAttribute("type", "text/javascript");
12051 script.setAttribute("id", trans.scriptId);
12052 this.head.appendChild(script);
12054 this.trans = trans;
12056 callback.call(scope||this, null, arg, false);
12061 isLoading : function(){
12062 return this.trans ? true : false;
12066 * Abort the current server request.
12068 abort : function(){
12069 if(this.isLoading()){
12070 this.destroyTrans(this.trans);
12075 destroyTrans : function(trans, isLoaded){
12076 this.head.removeChild(document.getElementById(trans.scriptId));
12077 clearTimeout(trans.timeoutId);
12079 window[trans.cb] = undefined;
12081 delete window[trans.cb];
12084 // if hasn't been loaded, wait for load to remove it to prevent script error
12085 window[trans.cb] = function(){
12086 window[trans.cb] = undefined;
12088 delete window[trans.cb];
12095 handleResponse : function(o, trans){
12096 this.trans = false;
12097 this.destroyTrans(trans, true);
12100 result = trans.reader.readRecords(o);
12102 this.fireEvent("loadexception", this, o, trans.arg, e);
12103 trans.callback.call(trans.scope||window, null, trans.arg, false);
12106 this.fireEvent("load", this, o, trans.arg);
12107 trans.callback.call(trans.scope||window, result, trans.arg, true);
12111 handleFailure : function(trans){
12112 this.trans = false;
12113 this.destroyTrans(trans, false);
12114 this.fireEvent("loadexception", this, null, trans.arg);
12115 trans.callback.call(trans.scope||window, null, trans.arg, false);
12119 * Ext JS Library 1.1.1
12120 * Copyright(c) 2006-2007, Ext JS, LLC.
12122 * Originally Released Under LGPL - original licence link has changed is not relivant.
12125 * <script type="text/javascript">
12129 * @class Roo.data.JsonReader
12130 * @extends Roo.data.DataReader
12131 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12132 * based on mappings in a provided Roo.data.Record constructor.
12134 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12135 * in the reply previously.
12140 var RecordDef = Roo.data.Record.create([
12141 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12142 {name: 'occupation'} // This field will use "occupation" as the mapping.
12144 var myReader = new Roo.data.JsonReader({
12145 totalProperty: "results", // The property which contains the total dataset size (optional)
12146 root: "rows", // The property which contains an Array of row objects
12147 id: "id" // The property within each row object that provides an ID for the record (optional)
12151 * This would consume a JSON file like this:
12153 { 'results': 2, 'rows': [
12154 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12155 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12158 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12159 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12160 * paged from the remote server.
12161 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12162 * @cfg {String} root name of the property which contains the Array of row objects.
12163 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12164 * @cfg {Array} fields Array of field definition objects
12166 * Create a new JsonReader
12167 * @param {Object} meta Metadata configuration options
12168 * @param {Object} recordType Either an Array of field definition objects,
12169 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12171 Roo.data.JsonReader = function(meta, recordType){
12174 // set some defaults:
12175 Roo.applyIf(meta, {
12176 totalProperty: 'total',
12177 successProperty : 'success',
12182 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12184 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12187 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12188 * Used by Store query builder to append _requestMeta to params.
12191 metaFromRemote : false,
12193 * This method is only used by a DataProxy which has retrieved data from a remote server.
12194 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12195 * @return {Object} data A data block which is used by an Roo.data.Store object as
12196 * a cache of Roo.data.Records.
12198 read : function(response){
12199 var json = response.responseText;
12201 var o = /* eval:var:o */ eval("("+json+")");
12203 throw {message: "JsonReader.read: Json object not found"};
12209 this.metaFromRemote = true;
12210 this.meta = o.metaData;
12211 this.recordType = Roo.data.Record.create(o.metaData.fields);
12212 this.onMetaChange(this.meta, this.recordType, o);
12214 return this.readRecords(o);
12217 // private function a store will implement
12218 onMetaChange : function(meta, recordType, o){
12225 simpleAccess: function(obj, subsc) {
12232 getJsonAccessor: function(){
12234 return function(expr) {
12236 return(re.test(expr))
12237 ? new Function("obj", "return obj." + expr)
12242 return Roo.emptyFn;
12247 * Create a data block containing Roo.data.Records from an XML document.
12248 * @param {Object} o An object which contains an Array of row objects in the property specified
12249 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12250 * which contains the total size of the dataset.
12251 * @return {Object} data A data block which is used by an Roo.data.Store object as
12252 * a cache of Roo.data.Records.
12254 readRecords : function(o){
12256 * After any data loads, the raw JSON data is available for further custom processing.
12260 var s = this.meta, Record = this.recordType,
12261 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12263 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12265 if(s.totalProperty) {
12266 this.getTotal = this.getJsonAccessor(s.totalProperty);
12268 if(s.successProperty) {
12269 this.getSuccess = this.getJsonAccessor(s.successProperty);
12271 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12273 var g = this.getJsonAccessor(s.id);
12274 this.getId = function(rec) {
12276 return (r === undefined || r === "") ? null : r;
12279 this.getId = function(){return null;};
12282 for(var jj = 0; jj < fl; jj++){
12284 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12285 this.ef[jj] = this.getJsonAccessor(map);
12289 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12290 if(s.totalProperty){
12291 var vt = parseInt(this.getTotal(o), 10);
12296 if(s.successProperty){
12297 var vs = this.getSuccess(o);
12298 if(vs === false || vs === 'false'){
12303 for(var i = 0; i < c; i++){
12306 var id = this.getId(n);
12307 for(var j = 0; j < fl; j++){
12309 var v = this.ef[j](n);
12311 Roo.log('missing convert for ' + f.name);
12315 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12317 var record = new Record(values, id);
12319 records[i] = record;
12325 totalRecords : totalRecords
12330 * Ext JS Library 1.1.1
12331 * Copyright(c) 2006-2007, Ext JS, LLC.
12333 * Originally Released Under LGPL - original licence link has changed is not relivant.
12336 * <script type="text/javascript">
12340 * @class Roo.data.ArrayReader
12341 * @extends Roo.data.DataReader
12342 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12343 * Each element of that Array represents a row of data fields. The
12344 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12345 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12349 var RecordDef = Roo.data.Record.create([
12350 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12351 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12353 var myReader = new Roo.data.ArrayReader({
12354 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12358 * This would consume an Array like this:
12360 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12362 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12364 * Create a new JsonReader
12365 * @param {Object} meta Metadata configuration options.
12366 * @param {Object} recordType Either an Array of field definition objects
12367 * as specified to {@link Roo.data.Record#create},
12368 * or an {@link Roo.data.Record} object
12369 * created using {@link Roo.data.Record#create}.
12371 Roo.data.ArrayReader = function(meta, recordType){
12372 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12375 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12377 * Create a data block containing Roo.data.Records from an XML document.
12378 * @param {Object} o An Array of row objects which represents the dataset.
12379 * @return {Object} data A data block which is used by an Roo.data.Store object as
12380 * a cache of Roo.data.Records.
12382 readRecords : function(o){
12383 var sid = this.meta ? this.meta.id : null;
12384 var recordType = this.recordType, fields = recordType.prototype.fields;
12387 for(var i = 0; i < root.length; i++){
12390 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12391 for(var j = 0, jlen = fields.length; j < jlen; j++){
12392 var f = fields.items[j];
12393 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12394 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12396 values[f.name] = v;
12398 var record = new recordType(values, id);
12400 records[records.length] = record;
12404 totalRecords : records.length
12413 * @class Roo.bootstrap.ComboBox
12414 * @extends Roo.bootstrap.TriggerField
12415 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12416 * @cfg {Boolean} append (true|false) default false
12417 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12418 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12419 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12420 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12421 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12422 * @cfg {Boolean} animate default true
12423 * @cfg {Boolean} emptyResultText only for touch device
12424 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12425 * @cfg {String} emptyTitle default ''
12427 * Create a new ComboBox.
12428 * @param {Object} config Configuration options
12430 Roo.bootstrap.ComboBox = function(config){
12431 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12435 * Fires when the dropdown list is expanded
12436 * @param {Roo.bootstrap.ComboBox} combo This combo box
12441 * Fires when the dropdown list is collapsed
12442 * @param {Roo.bootstrap.ComboBox} combo This combo box
12446 * @event beforeselect
12447 * Fires before a list item is selected. Return false to cancel the selection.
12448 * @param {Roo.bootstrap.ComboBox} combo This combo box
12449 * @param {Roo.data.Record} record The data record returned from the underlying store
12450 * @param {Number} index The index of the selected item in the dropdown list
12452 'beforeselect' : true,
12455 * Fires when a list item is selected
12456 * @param {Roo.bootstrap.ComboBox} combo This combo box
12457 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12458 * @param {Number} index The index of the selected item in the dropdown list
12462 * @event beforequery
12463 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12464 * The event object passed has these properties:
12465 * @param {Roo.bootstrap.ComboBox} combo This combo box
12466 * @param {String} query The query
12467 * @param {Boolean} forceAll true to force "all" query
12468 * @param {Boolean} cancel true to cancel the query
12469 * @param {Object} e The query event object
12471 'beforequery': true,
12474 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12475 * @param {Roo.bootstrap.ComboBox} combo This combo box
12480 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12481 * @param {Roo.bootstrap.ComboBox} combo This combo box
12482 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12487 * Fires when the remove value from the combobox array
12488 * @param {Roo.bootstrap.ComboBox} combo This combo box
12492 * @event afterremove
12493 * Fires when the remove value from the combobox array
12494 * @param {Roo.bootstrap.ComboBox} combo This combo box
12496 'afterremove' : true,
12498 * @event specialfilter
12499 * Fires when specialfilter
12500 * @param {Roo.bootstrap.ComboBox} combo This combo box
12502 'specialfilter' : true,
12505 * Fires when tick the element
12506 * @param {Roo.bootstrap.ComboBox} combo This combo box
12510 * @event touchviewdisplay
12511 * Fires when touch view require special display (default is using displayField)
12512 * @param {Roo.bootstrap.ComboBox} combo This combo box
12513 * @param {Object} cfg set html .
12515 'touchviewdisplay' : true
12520 this.tickItems = [];
12522 this.selectedIndex = -1;
12523 if(this.mode == 'local'){
12524 if(config.queryDelay === undefined){
12525 this.queryDelay = 10;
12527 if(config.minChars === undefined){
12533 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12536 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12537 * rendering into an Roo.Editor, defaults to false)
12540 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12541 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12544 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12547 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12548 * the dropdown list (defaults to undefined, with no header element)
12552 * @cfg {String/Roo.Template} tpl The template to use to render the output
12556 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12558 listWidth: undefined,
12560 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12561 * mode = 'remote' or 'text' if mode = 'local')
12563 displayField: undefined,
12566 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12567 * mode = 'remote' or 'value' if mode = 'local').
12568 * Note: use of a valueField requires the user make a selection
12569 * in order for a value to be mapped.
12571 valueField: undefined,
12573 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12578 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12579 * field's data value (defaults to the underlying DOM element's name)
12581 hiddenName: undefined,
12583 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12587 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12589 selectedClass: 'active',
12592 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12596 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12597 * anchor positions (defaults to 'tl-bl')
12599 listAlign: 'tl-bl?',
12601 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12605 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12606 * query specified by the allQuery config option (defaults to 'query')
12608 triggerAction: 'query',
12610 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12611 * (defaults to 4, does not apply if editable = false)
12615 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12616 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12620 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12621 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12625 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12626 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12630 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12631 * when editable = true (defaults to false)
12633 selectOnFocus:false,
12635 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12637 queryParam: 'query',
12639 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12640 * when mode = 'remote' (defaults to 'Loading...')
12642 loadingText: 'Loading...',
12644 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12648 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12652 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12653 * traditional select (defaults to true)
12657 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12661 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12665 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12666 * listWidth has a higher value)
12670 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12671 * allow the user to set arbitrary text into the field (defaults to false)
12673 forceSelection:false,
12675 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12676 * if typeAhead = true (defaults to 250)
12678 typeAheadDelay : 250,
12680 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12681 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12683 valueNotFoundText : undefined,
12685 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12687 blockFocus : false,
12690 * @cfg {Boolean} disableClear Disable showing of clear button.
12692 disableClear : false,
12694 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12696 alwaysQuery : false,
12699 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12704 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12706 invalidClass : "has-warning",
12709 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12711 validClass : "has-success",
12714 * @cfg {Boolean} specialFilter (true|false) special filter default false
12716 specialFilter : false,
12719 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12721 mobileTouchView : true,
12724 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12726 useNativeIOS : false,
12728 ios_options : false,
12740 btnPosition : 'right',
12741 triggerList : true,
12742 showToggleBtn : true,
12744 emptyResultText: 'Empty',
12745 triggerText : 'Select',
12748 // element that contains real text value.. (when hidden is used..)
12750 getAutoCreate : function()
12755 * Render classic select for iso
12758 if(Roo.isIOS && this.useNativeIOS){
12759 cfg = this.getAutoCreateNativeIOS();
12767 if(Roo.isTouch && this.mobileTouchView){
12768 cfg = this.getAutoCreateTouchView();
12775 if(!this.tickable){
12776 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12781 * ComboBox with tickable selections
12784 var align = this.labelAlign || this.parentLabelAlign();
12787 cls : 'form-group roo-combobox-tickable' //input-group
12790 var btn_text_select = '';
12791 var btn_text_done = '';
12792 var btn_text_cancel = '';
12794 if (this.btn_text_show) {
12795 btn_text_select = 'Select';
12796 btn_text_done = 'Done';
12797 btn_text_cancel = 'Cancel';
12802 cls : 'tickable-buttons',
12807 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12808 //html : this.triggerText
12809 html: btn_text_select
12815 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12817 html: btn_text_done
12823 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12825 html: btn_text_cancel
12831 buttons.cn.unshift({
12833 cls: 'roo-select2-search-field-input'
12839 Roo.each(buttons.cn, function(c){
12841 c.cls += ' btn-' + _this.size;
12844 if (_this.disabled) {
12855 cls: 'form-hidden-field'
12859 cls: 'roo-select2-choices',
12863 cls: 'roo-select2-search-field',
12874 cls: 'roo-select2-container input-group roo-select2-container-multi',
12879 // cls: 'typeahead typeahead-long dropdown-menu',
12880 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12885 if(this.hasFeedback && !this.allowBlank){
12889 cls: 'glyphicon form-control-feedback'
12892 combobox.cn.push(feedback);
12896 if (align ==='left' && this.fieldLabel.length) {
12898 cfg.cls += ' roo-form-group-label-left';
12903 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12904 tooltip : 'This field is required'
12909 cls : 'control-label',
12910 html : this.fieldLabel
12922 var labelCfg = cfg.cn[1];
12923 var contentCfg = cfg.cn[2];
12926 if(this.indicatorpos == 'right'){
12932 cls : 'control-label',
12936 html : this.fieldLabel
12940 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12941 tooltip : 'This field is required'
12956 labelCfg = cfg.cn[0];
12957 contentCfg = cfg.cn[1];
12961 if(this.labelWidth > 12){
12962 labelCfg.style = "width: " + this.labelWidth + 'px';
12965 if(this.labelWidth < 13 && this.labelmd == 0){
12966 this.labelmd = this.labelWidth;
12969 if(this.labellg > 0){
12970 labelCfg.cls += ' col-lg-' + this.labellg;
12971 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12974 if(this.labelmd > 0){
12975 labelCfg.cls += ' col-md-' + this.labelmd;
12976 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12979 if(this.labelsm > 0){
12980 labelCfg.cls += ' col-sm-' + this.labelsm;
12981 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12984 if(this.labelxs > 0){
12985 labelCfg.cls += ' col-xs-' + this.labelxs;
12986 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12990 } else if ( this.fieldLabel.length) {
12991 // Roo.log(" label");
12995 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12996 tooltip : 'This field is required'
13000 //cls : 'input-group-addon',
13001 html : this.fieldLabel
13006 if(this.indicatorpos == 'right'){
13010 //cls : 'input-group-addon',
13011 html : this.fieldLabel
13015 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13016 tooltip : 'This field is required'
13025 // Roo.log(" no label && no align");
13032 ['xs','sm','md','lg'].map(function(size){
13033 if (settings[size]) {
13034 cfg.cls += ' col-' + size + '-' + settings[size];
13042 _initEventsCalled : false,
13045 initEvents: function()
13047 if (this._initEventsCalled) { // as we call render... prevent looping...
13050 this._initEventsCalled = true;
13053 throw "can not find store for combo";
13056 this.indicator = this.indicatorEl();
13058 this.store = Roo.factory(this.store, Roo.data);
13059 this.store.parent = this;
13061 // if we are building from html. then this element is so complex, that we can not really
13062 // use the rendered HTML.
13063 // so we have to trash and replace the previous code.
13064 if (Roo.XComponent.build_from_html) {
13065 // remove this element....
13066 var e = this.el.dom, k=0;
13067 while (e ) { e = e.previousSibling; ++k;}
13072 this.rendered = false;
13074 this.render(this.parent().getChildContainer(true), k);
13077 if(Roo.isIOS && this.useNativeIOS){
13078 this.initIOSView();
13086 if(Roo.isTouch && this.mobileTouchView){
13087 this.initTouchView();
13092 this.initTickableEvents();
13096 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13098 if(this.hiddenName){
13100 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13102 this.hiddenField.dom.value =
13103 this.hiddenValue !== undefined ? this.hiddenValue :
13104 this.value !== undefined ? this.value : '';
13106 // prevent input submission
13107 this.el.dom.removeAttribute('name');
13108 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13113 // this.el.dom.setAttribute('autocomplete', 'off');
13116 var cls = 'x-combo-list';
13118 //this.list = new Roo.Layer({
13119 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13125 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13126 _this.list.setWidth(lw);
13129 this.list.on('mouseover', this.onViewOver, this);
13130 this.list.on('mousemove', this.onViewMove, this);
13131 this.list.on('scroll', this.onViewScroll, this);
13134 this.list.swallowEvent('mousewheel');
13135 this.assetHeight = 0;
13138 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13139 this.assetHeight += this.header.getHeight();
13142 this.innerList = this.list.createChild({cls:cls+'-inner'});
13143 this.innerList.on('mouseover', this.onViewOver, this);
13144 this.innerList.on('mousemove', this.onViewMove, this);
13145 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13147 if(this.allowBlank && !this.pageSize && !this.disableClear){
13148 this.footer = this.list.createChild({cls:cls+'-ft'});
13149 this.pageTb = new Roo.Toolbar(this.footer);
13153 this.footer = this.list.createChild({cls:cls+'-ft'});
13154 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13155 {pageSize: this.pageSize});
13159 if (this.pageTb && this.allowBlank && !this.disableClear) {
13161 this.pageTb.add(new Roo.Toolbar.Fill(), {
13162 cls: 'x-btn-icon x-btn-clear',
13164 handler: function()
13167 _this.clearValue();
13168 _this.onSelect(false, -1);
13173 this.assetHeight += this.footer.getHeight();
13178 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13181 this.view = new Roo.View(this.list, this.tpl, {
13182 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13184 //this.view.wrapEl.setDisplayed(false);
13185 this.view.on('click', this.onViewClick, this);
13188 this.store.on('beforeload', this.onBeforeLoad, this);
13189 this.store.on('load', this.onLoad, this);
13190 this.store.on('loadexception', this.onLoadException, this);
13192 if(this.resizable){
13193 this.resizer = new Roo.Resizable(this.list, {
13194 pinned:true, handles:'se'
13196 this.resizer.on('resize', function(r, w, h){
13197 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13198 this.listWidth = w;
13199 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13200 this.restrictHeight();
13202 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13205 if(!this.editable){
13206 this.editable = true;
13207 this.setEditable(false);
13212 if (typeof(this.events.add.listeners) != 'undefined') {
13214 this.addicon = this.wrap.createChild(
13215 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13217 this.addicon.on('click', function(e) {
13218 this.fireEvent('add', this);
13221 if (typeof(this.events.edit.listeners) != 'undefined') {
13223 this.editicon = this.wrap.createChild(
13224 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13225 if (this.addicon) {
13226 this.editicon.setStyle('margin-left', '40px');
13228 this.editicon.on('click', function(e) {
13230 // we fire even if inothing is selected..
13231 this.fireEvent('edit', this, this.lastData );
13237 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13238 "up" : function(e){
13239 this.inKeyMode = true;
13243 "down" : function(e){
13244 if(!this.isExpanded()){
13245 this.onTriggerClick();
13247 this.inKeyMode = true;
13252 "enter" : function(e){
13253 // this.onViewClick();
13257 if(this.fireEvent("specialkey", this, e)){
13258 this.onViewClick(false);
13264 "esc" : function(e){
13268 "tab" : function(e){
13271 if(this.fireEvent("specialkey", this, e)){
13272 this.onViewClick(false);
13280 doRelay : function(foo, bar, hname){
13281 if(hname == 'down' || this.scope.isExpanded()){
13282 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13291 this.queryDelay = Math.max(this.queryDelay || 10,
13292 this.mode == 'local' ? 10 : 250);
13295 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13297 if(this.typeAhead){
13298 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13300 if(this.editable !== false){
13301 this.inputEl().on("keyup", this.onKeyUp, this);
13303 if(this.forceSelection){
13304 this.inputEl().on('blur', this.doForce, this);
13308 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13309 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13313 initTickableEvents: function()
13317 if(this.hiddenName){
13319 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13321 this.hiddenField.dom.value =
13322 this.hiddenValue !== undefined ? this.hiddenValue :
13323 this.value !== undefined ? this.value : '';
13325 // prevent input submission
13326 this.el.dom.removeAttribute('name');
13327 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13332 // this.list = this.el.select('ul.dropdown-menu',true).first();
13334 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13335 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13336 if(this.triggerList){
13337 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13340 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13341 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13343 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13344 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13346 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13347 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13349 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13350 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13351 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13354 this.cancelBtn.hide();
13359 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13360 _this.list.setWidth(lw);
13363 this.list.on('mouseover', this.onViewOver, this);
13364 this.list.on('mousemove', this.onViewMove, this);
13366 this.list.on('scroll', this.onViewScroll, this);
13369 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>';
13372 this.view = new Roo.View(this.list, this.tpl, {
13373 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13376 //this.view.wrapEl.setDisplayed(false);
13377 this.view.on('click', this.onViewClick, this);
13381 this.store.on('beforeload', this.onBeforeLoad, this);
13382 this.store.on('load', this.onLoad, this);
13383 this.store.on('loadexception', this.onLoadException, this);
13386 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13387 "up" : function(e){
13388 this.inKeyMode = true;
13392 "down" : function(e){
13393 this.inKeyMode = true;
13397 "enter" : function(e){
13398 if(this.fireEvent("specialkey", this, e)){
13399 this.onViewClick(false);
13405 "esc" : function(e){
13406 this.onTickableFooterButtonClick(e, false, false);
13409 "tab" : function(e){
13410 this.fireEvent("specialkey", this, e);
13412 this.onTickableFooterButtonClick(e, false, false);
13419 doRelay : function(e, fn, key){
13420 if(this.scope.isExpanded()){
13421 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13430 this.queryDelay = Math.max(this.queryDelay || 10,
13431 this.mode == 'local' ? 10 : 250);
13434 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13436 if(this.typeAhead){
13437 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13440 if(this.editable !== false){
13441 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13444 this.indicator = this.indicatorEl();
13446 if(this.indicator){
13447 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13448 this.indicator.hide();
13453 onDestroy : function(){
13455 this.view.setStore(null);
13456 this.view.el.removeAllListeners();
13457 this.view.el.remove();
13458 this.view.purgeListeners();
13461 this.list.dom.innerHTML = '';
13465 this.store.un('beforeload', this.onBeforeLoad, this);
13466 this.store.un('load', this.onLoad, this);
13467 this.store.un('loadexception', this.onLoadException, this);
13469 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13473 fireKey : function(e){
13474 if(e.isNavKeyPress() && !this.list.isVisible()){
13475 this.fireEvent("specialkey", this, e);
13480 onResize: function(w, h){
13481 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13483 // if(typeof w != 'number'){
13484 // // we do not handle it!?!?
13487 // var tw = this.trigger.getWidth();
13488 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13489 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13491 // this.inputEl().setWidth( this.adjustWidth('input', x));
13493 // //this.trigger.setStyle('left', x+'px');
13495 // if(this.list && this.listWidth === undefined){
13496 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13497 // this.list.setWidth(lw);
13498 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13506 * Allow or prevent the user from directly editing the field text. If false is passed,
13507 * the user will only be able to select from the items defined in the dropdown list. This method
13508 * is the runtime equivalent of setting the 'editable' config option at config time.
13509 * @param {Boolean} value True to allow the user to directly edit the field text
13511 setEditable : function(value){
13512 if(value == this.editable){
13515 this.editable = value;
13517 this.inputEl().dom.setAttribute('readOnly', true);
13518 this.inputEl().on('mousedown', this.onTriggerClick, this);
13519 this.inputEl().addClass('x-combo-noedit');
13521 this.inputEl().dom.setAttribute('readOnly', false);
13522 this.inputEl().un('mousedown', this.onTriggerClick, this);
13523 this.inputEl().removeClass('x-combo-noedit');
13529 onBeforeLoad : function(combo,opts){
13530 if(!this.hasFocus){
13534 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13536 this.restrictHeight();
13537 this.selectedIndex = -1;
13541 onLoad : function(){
13543 this.hasQuery = false;
13545 if(!this.hasFocus){
13549 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13550 this.loading.hide();
13553 if(this.store.getCount() > 0){
13556 this.restrictHeight();
13557 if(this.lastQuery == this.allQuery){
13558 if(this.editable && !this.tickable){
13559 this.inputEl().dom.select();
13563 !this.selectByValue(this.value, true) &&
13566 !this.store.lastOptions ||
13567 typeof(this.store.lastOptions.add) == 'undefined' ||
13568 this.store.lastOptions.add != true
13571 this.select(0, true);
13574 if(this.autoFocus){
13577 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13578 this.taTask.delay(this.typeAheadDelay);
13582 this.onEmptyResults();
13588 onLoadException : function()
13590 this.hasQuery = false;
13592 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13593 this.loading.hide();
13596 if(this.tickable && this.editable){
13601 // only causes errors at present
13602 //Roo.log(this.store.reader.jsonData);
13603 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13605 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13611 onTypeAhead : function(){
13612 if(this.store.getCount() > 0){
13613 var r = this.store.getAt(0);
13614 var newValue = r.data[this.displayField];
13615 var len = newValue.length;
13616 var selStart = this.getRawValue().length;
13618 if(selStart != len){
13619 this.setRawValue(newValue);
13620 this.selectText(selStart, newValue.length);
13626 onSelect : function(record, index){
13628 if(this.fireEvent('beforeselect', this, record, index) !== false){
13630 this.setFromData(index > -1 ? record.data : false);
13633 this.fireEvent('select', this, record, index);
13638 * Returns the currently selected field value or empty string if no value is set.
13639 * @return {String} value The selected value
13641 getValue : function()
13643 if(Roo.isIOS && this.useNativeIOS){
13644 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13648 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13651 if(this.valueField){
13652 return typeof this.value != 'undefined' ? this.value : '';
13654 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13658 getRawValue : function()
13660 if(Roo.isIOS && this.useNativeIOS){
13661 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13664 var v = this.inputEl().getValue();
13670 * Clears any text/value currently set in the field
13672 clearValue : function(){
13674 if(this.hiddenField){
13675 this.hiddenField.dom.value = '';
13678 this.setRawValue('');
13679 this.lastSelectionText = '';
13680 this.lastData = false;
13682 var close = this.closeTriggerEl();
13693 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13694 * will be displayed in the field. If the value does not match the data value of an existing item,
13695 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13696 * Otherwise the field will be blank (although the value will still be set).
13697 * @param {String} value The value to match
13699 setValue : function(v)
13701 if(Roo.isIOS && this.useNativeIOS){
13702 this.setIOSValue(v);
13712 if(this.valueField){
13713 var r = this.findRecord(this.valueField, v);
13715 text = r.data[this.displayField];
13716 }else if(this.valueNotFoundText !== undefined){
13717 text = this.valueNotFoundText;
13720 this.lastSelectionText = text;
13721 if(this.hiddenField){
13722 this.hiddenField.dom.value = v;
13724 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13727 var close = this.closeTriggerEl();
13730 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13736 * @property {Object} the last set data for the element
13741 * Sets the value of the field based on a object which is related to the record format for the store.
13742 * @param {Object} value the value to set as. or false on reset?
13744 setFromData : function(o){
13751 var dv = ''; // display value
13752 var vv = ''; // value value..
13754 if (this.displayField) {
13755 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13757 // this is an error condition!!!
13758 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13761 if(this.valueField){
13762 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13765 var close = this.closeTriggerEl();
13768 if(dv.length || vv * 1 > 0){
13770 this.blockFocus=true;
13776 if(this.hiddenField){
13777 this.hiddenField.dom.value = vv;
13779 this.lastSelectionText = dv;
13780 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13784 // no hidden field.. - we store the value in 'value', but still display
13785 // display field!!!!
13786 this.lastSelectionText = dv;
13787 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13794 reset : function(){
13795 // overridden so that last data is reset..
13802 this.setValue(this.originalValue);
13803 //this.clearInvalid();
13804 this.lastData = false;
13806 this.view.clearSelections();
13812 findRecord : function(prop, value){
13814 if(this.store.getCount() > 0){
13815 this.store.each(function(r){
13816 if(r.data[prop] == value){
13826 getName: function()
13828 // returns hidden if it's set..
13829 if (!this.rendered) {return ''};
13830 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13834 onViewMove : function(e, t){
13835 this.inKeyMode = false;
13839 onViewOver : function(e, t){
13840 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13843 var item = this.view.findItemFromChild(t);
13846 var index = this.view.indexOf(item);
13847 this.select(index, false);
13852 onViewClick : function(view, doFocus, el, e)
13854 var index = this.view.getSelectedIndexes()[0];
13856 var r = this.store.getAt(index);
13860 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13867 Roo.each(this.tickItems, function(v,k){
13869 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13871 _this.tickItems.splice(k, 1);
13873 if(typeof(e) == 'undefined' && view == false){
13874 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13886 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13887 this.tickItems.push(r.data);
13890 if(typeof(e) == 'undefined' && view == false){
13891 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13898 this.onSelect(r, index);
13900 if(doFocus !== false && !this.blockFocus){
13901 this.inputEl().focus();
13906 restrictHeight : function(){
13907 //this.innerList.dom.style.height = '';
13908 //var inner = this.innerList.dom;
13909 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13910 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13911 //this.list.beginUpdate();
13912 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13913 this.list.alignTo(this.inputEl(), this.listAlign);
13914 this.list.alignTo(this.inputEl(), this.listAlign);
13915 //this.list.endUpdate();
13919 onEmptyResults : function(){
13921 if(this.tickable && this.editable){
13922 this.restrictHeight();
13930 * Returns true if the dropdown list is expanded, else false.
13932 isExpanded : function(){
13933 return this.list.isVisible();
13937 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13938 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13939 * @param {String} value The data value of the item to select
13940 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13941 * selected item if it is not currently in view (defaults to true)
13942 * @return {Boolean} True if the value matched an item in the list, else false
13944 selectByValue : function(v, scrollIntoView){
13945 if(v !== undefined && v !== null){
13946 var r = this.findRecord(this.valueField || this.displayField, v);
13948 this.select(this.store.indexOf(r), scrollIntoView);
13956 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13957 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13958 * @param {Number} index The zero-based index of the list item to select
13959 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13960 * selected item if it is not currently in view (defaults to true)
13962 select : function(index, scrollIntoView){
13963 this.selectedIndex = index;
13964 this.view.select(index);
13965 if(scrollIntoView !== false){
13966 var el = this.view.getNode(index);
13968 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13971 this.list.scrollChildIntoView(el, false);
13977 selectNext : function(){
13978 var ct = this.store.getCount();
13980 if(this.selectedIndex == -1){
13982 }else if(this.selectedIndex < ct-1){
13983 this.select(this.selectedIndex+1);
13989 selectPrev : function(){
13990 var ct = this.store.getCount();
13992 if(this.selectedIndex == -1){
13994 }else if(this.selectedIndex != 0){
13995 this.select(this.selectedIndex-1);
14001 onKeyUp : function(e){
14002 if(this.editable !== false && !e.isSpecialKey()){
14003 this.lastKey = e.getKey();
14004 this.dqTask.delay(this.queryDelay);
14009 validateBlur : function(){
14010 return !this.list || !this.list.isVisible();
14014 initQuery : function(){
14016 var v = this.getRawValue();
14018 if(this.tickable && this.editable){
14019 v = this.tickableInputEl().getValue();
14026 doForce : function(){
14027 if(this.inputEl().dom.value.length > 0){
14028 this.inputEl().dom.value =
14029 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14035 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14036 * query allowing the query action to be canceled if needed.
14037 * @param {String} query The SQL query to execute
14038 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14039 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14040 * saved in the current store (defaults to false)
14042 doQuery : function(q, forceAll){
14044 if(q === undefined || q === null){
14049 forceAll: forceAll,
14053 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14058 forceAll = qe.forceAll;
14059 if(forceAll === true || (q.length >= this.minChars)){
14061 this.hasQuery = true;
14063 if(this.lastQuery != q || this.alwaysQuery){
14064 this.lastQuery = q;
14065 if(this.mode == 'local'){
14066 this.selectedIndex = -1;
14068 this.store.clearFilter();
14071 if(this.specialFilter){
14072 this.fireEvent('specialfilter', this);
14077 this.store.filter(this.displayField, q);
14080 this.store.fireEvent("datachanged", this.store);
14087 this.store.baseParams[this.queryParam] = q;
14089 var options = {params : this.getParams(q)};
14092 options.add = true;
14093 options.params.start = this.page * this.pageSize;
14096 this.store.load(options);
14099 * this code will make the page width larger, at the beginning, the list not align correctly,
14100 * we should expand the list on onLoad
14101 * so command out it
14106 this.selectedIndex = -1;
14111 this.loadNext = false;
14115 getParams : function(q){
14117 //p[this.queryParam] = q;
14121 p.limit = this.pageSize;
14127 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14129 collapse : function(){
14130 if(!this.isExpanded()){
14136 this.hasFocus = false;
14140 this.cancelBtn.hide();
14141 this.trigger.show();
14144 this.tickableInputEl().dom.value = '';
14145 this.tickableInputEl().blur();
14150 Roo.get(document).un('mousedown', this.collapseIf, this);
14151 Roo.get(document).un('mousewheel', this.collapseIf, this);
14152 if (!this.editable) {
14153 Roo.get(document).un('keydown', this.listKeyPress, this);
14155 this.fireEvent('collapse', this);
14161 collapseIf : function(e){
14162 var in_combo = e.within(this.el);
14163 var in_list = e.within(this.list);
14164 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14166 if (in_combo || in_list || is_list) {
14167 //e.stopPropagation();
14172 this.onTickableFooterButtonClick(e, false, false);
14180 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14182 expand : function(){
14184 if(this.isExpanded() || !this.hasFocus){
14188 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14189 this.list.setWidth(lw);
14195 this.restrictHeight();
14199 this.tickItems = Roo.apply([], this.item);
14202 this.cancelBtn.show();
14203 this.trigger.hide();
14206 this.tickableInputEl().focus();
14211 Roo.get(document).on('mousedown', this.collapseIf, this);
14212 Roo.get(document).on('mousewheel', this.collapseIf, this);
14213 if (!this.editable) {
14214 Roo.get(document).on('keydown', this.listKeyPress, this);
14217 this.fireEvent('expand', this);
14221 // Implements the default empty TriggerField.onTriggerClick function
14222 onTriggerClick : function(e)
14224 Roo.log('trigger click');
14226 if(this.disabled || !this.triggerList){
14231 this.loadNext = false;
14233 if(this.isExpanded()){
14235 if (!this.blockFocus) {
14236 this.inputEl().focus();
14240 this.hasFocus = true;
14241 if(this.triggerAction == 'all') {
14242 this.doQuery(this.allQuery, true);
14244 this.doQuery(this.getRawValue());
14246 if (!this.blockFocus) {
14247 this.inputEl().focus();
14252 onTickableTriggerClick : function(e)
14259 this.loadNext = false;
14260 this.hasFocus = true;
14262 if(this.triggerAction == 'all') {
14263 this.doQuery(this.allQuery, true);
14265 this.doQuery(this.getRawValue());
14269 onSearchFieldClick : function(e)
14271 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14272 this.onTickableFooterButtonClick(e, false, false);
14276 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14281 this.loadNext = false;
14282 this.hasFocus = true;
14284 if(this.triggerAction == 'all') {
14285 this.doQuery(this.allQuery, true);
14287 this.doQuery(this.getRawValue());
14291 listKeyPress : function(e)
14293 //Roo.log('listkeypress');
14294 // scroll to first matching element based on key pres..
14295 if (e.isSpecialKey()) {
14298 var k = String.fromCharCode(e.getKey()).toUpperCase();
14301 var csel = this.view.getSelectedNodes();
14302 var cselitem = false;
14304 var ix = this.view.indexOf(csel[0]);
14305 cselitem = this.store.getAt(ix);
14306 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14312 this.store.each(function(v) {
14314 // start at existing selection.
14315 if (cselitem.id == v.id) {
14321 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14322 match = this.store.indexOf(v);
14328 if (match === false) {
14329 return true; // no more action?
14332 this.view.select(match);
14333 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14334 sn.scrollIntoView(sn.dom.parentNode, false);
14337 onViewScroll : function(e, t){
14339 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){
14343 this.hasQuery = true;
14345 this.loading = this.list.select('.loading', true).first();
14347 if(this.loading === null){
14348 this.list.createChild({
14350 cls: 'loading roo-select2-more-results roo-select2-active',
14351 html: 'Loading more results...'
14354 this.loading = this.list.select('.loading', true).first();
14356 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14358 this.loading.hide();
14361 this.loading.show();
14366 this.loadNext = true;
14368 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14373 addItem : function(o)
14375 var dv = ''; // display value
14377 if (this.displayField) {
14378 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14380 // this is an error condition!!!
14381 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14388 var choice = this.choices.createChild({
14390 cls: 'roo-select2-search-choice',
14399 cls: 'roo-select2-search-choice-close fa fa-times',
14404 }, this.searchField);
14406 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14408 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14416 this.inputEl().dom.value = '';
14421 onRemoveItem : function(e, _self, o)
14423 e.preventDefault();
14425 this.lastItem = Roo.apply([], this.item);
14427 var index = this.item.indexOf(o.data) * 1;
14430 Roo.log('not this item?!');
14434 this.item.splice(index, 1);
14439 this.fireEvent('remove', this, e);
14445 syncValue : function()
14447 if(!this.item.length){
14454 Roo.each(this.item, function(i){
14455 if(_this.valueField){
14456 value.push(i[_this.valueField]);
14463 this.value = value.join(',');
14465 if(this.hiddenField){
14466 this.hiddenField.dom.value = this.value;
14469 this.store.fireEvent("datachanged", this.store);
14474 clearItem : function()
14476 if(!this.multiple){
14482 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14490 if(this.tickable && !Roo.isTouch){
14491 this.view.refresh();
14495 inputEl: function ()
14497 if(Roo.isIOS && this.useNativeIOS){
14498 return this.el.select('select.roo-ios-select', true).first();
14501 if(Roo.isTouch && this.mobileTouchView){
14502 return this.el.select('input.form-control',true).first();
14506 return this.searchField;
14509 return this.el.select('input.form-control',true).first();
14512 onTickableFooterButtonClick : function(e, btn, el)
14514 e.preventDefault();
14516 this.lastItem = Roo.apply([], this.item);
14518 if(btn && btn.name == 'cancel'){
14519 this.tickItems = Roo.apply([], this.item);
14528 Roo.each(this.tickItems, function(o){
14536 validate : function()
14538 var v = this.getRawValue();
14541 v = this.getValue();
14544 if(this.disabled || this.allowBlank || v.length){
14549 this.markInvalid();
14553 tickableInputEl : function()
14555 if(!this.tickable || !this.editable){
14556 return this.inputEl();
14559 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14563 getAutoCreateTouchView : function()
14568 cls: 'form-group' //input-group
14574 type : this.inputType,
14575 cls : 'form-control x-combo-noedit',
14576 autocomplete: 'new-password',
14577 placeholder : this.placeholder || '',
14582 input.name = this.name;
14586 input.cls += ' input-' + this.size;
14589 if (this.disabled) {
14590 input.disabled = true;
14601 inputblock.cls += ' input-group';
14603 inputblock.cn.unshift({
14605 cls : 'input-group-addon',
14610 if(this.removable && !this.multiple){
14611 inputblock.cls += ' roo-removable';
14613 inputblock.cn.push({
14616 cls : 'roo-combo-removable-btn close'
14620 if(this.hasFeedback && !this.allowBlank){
14622 inputblock.cls += ' has-feedback';
14624 inputblock.cn.push({
14626 cls: 'glyphicon form-control-feedback'
14633 inputblock.cls += (this.before) ? '' : ' input-group';
14635 inputblock.cn.push({
14637 cls : 'input-group-addon',
14648 cls: 'form-hidden-field'
14662 cls: 'form-hidden-field'
14666 cls: 'roo-select2-choices',
14670 cls: 'roo-select2-search-field',
14683 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14689 if(!this.multiple && this.showToggleBtn){
14696 if (this.caret != false) {
14699 cls: 'fa fa-' + this.caret
14706 cls : 'input-group-addon btn dropdown-toggle',
14711 cls: 'combobox-clear',
14725 combobox.cls += ' roo-select2-container-multi';
14728 var align = this.labelAlign || this.parentLabelAlign();
14730 if (align ==='left' && this.fieldLabel.length) {
14735 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14736 tooltip : 'This field is required'
14740 cls : 'control-label',
14741 html : this.fieldLabel
14752 var labelCfg = cfg.cn[1];
14753 var contentCfg = cfg.cn[2];
14756 if(this.indicatorpos == 'right'){
14761 cls : 'control-label',
14765 html : this.fieldLabel
14769 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14770 tooltip : 'This field is required'
14783 labelCfg = cfg.cn[0];
14784 contentCfg = cfg.cn[1];
14789 if(this.labelWidth > 12){
14790 labelCfg.style = "width: " + this.labelWidth + 'px';
14793 if(this.labelWidth < 13 && this.labelmd == 0){
14794 this.labelmd = this.labelWidth;
14797 if(this.labellg > 0){
14798 labelCfg.cls += ' col-lg-' + this.labellg;
14799 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14802 if(this.labelmd > 0){
14803 labelCfg.cls += ' col-md-' + this.labelmd;
14804 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14807 if(this.labelsm > 0){
14808 labelCfg.cls += ' col-sm-' + this.labelsm;
14809 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14812 if(this.labelxs > 0){
14813 labelCfg.cls += ' col-xs-' + this.labelxs;
14814 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14818 } else if ( this.fieldLabel.length) {
14822 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14823 tooltip : 'This field is required'
14827 cls : 'control-label',
14828 html : this.fieldLabel
14839 if(this.indicatorpos == 'right'){
14843 cls : 'control-label',
14844 html : this.fieldLabel,
14848 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14849 tooltip : 'This field is required'
14866 var settings = this;
14868 ['xs','sm','md','lg'].map(function(size){
14869 if (settings[size]) {
14870 cfg.cls += ' col-' + size + '-' + settings[size];
14877 initTouchView : function()
14879 this.renderTouchView();
14881 this.touchViewEl.on('scroll', function(){
14882 this.el.dom.scrollTop = 0;
14885 this.originalValue = this.getValue();
14887 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14889 this.inputEl().on("click", this.showTouchView, this);
14890 if (this.triggerEl) {
14891 this.triggerEl.on("click", this.showTouchView, this);
14895 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14896 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14898 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14900 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14901 this.store.on('load', this.onTouchViewLoad, this);
14902 this.store.on('loadexception', this.onTouchViewLoadException, this);
14904 if(this.hiddenName){
14906 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14908 this.hiddenField.dom.value =
14909 this.hiddenValue !== undefined ? this.hiddenValue :
14910 this.value !== undefined ? this.value : '';
14912 this.el.dom.removeAttribute('name');
14913 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14917 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14918 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14921 if(this.removable && !this.multiple){
14922 var close = this.closeTriggerEl();
14924 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14925 close.on('click', this.removeBtnClick, this, close);
14929 * fix the bug in Safari iOS8
14931 this.inputEl().on("focus", function(e){
14932 document.activeElement.blur();
14940 renderTouchView : function()
14942 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14943 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14945 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14946 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14948 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14949 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14950 this.touchViewBodyEl.setStyle('overflow', 'auto');
14952 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14953 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14955 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14956 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14960 showTouchView : function()
14966 this.touchViewHeaderEl.hide();
14968 if(this.modalTitle.length){
14969 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14970 this.touchViewHeaderEl.show();
14973 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14974 this.touchViewEl.show();
14976 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
14978 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14979 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14981 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14983 if(this.modalTitle.length){
14984 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14987 this.touchViewBodyEl.setHeight(bodyHeight);
14991 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14993 this.touchViewEl.addClass('in');
14996 this.doTouchViewQuery();
15000 hideTouchView : function()
15002 this.touchViewEl.removeClass('in');
15006 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15008 this.touchViewEl.setStyle('display', 'none');
15013 setTouchViewValue : function()
15020 Roo.each(this.tickItems, function(o){
15025 this.hideTouchView();
15028 doTouchViewQuery : function()
15037 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15041 if(!this.alwaysQuery || this.mode == 'local'){
15042 this.onTouchViewLoad();
15049 onTouchViewBeforeLoad : function(combo,opts)
15055 onTouchViewLoad : function()
15057 if(this.store.getCount() < 1){
15058 this.onTouchViewEmptyResults();
15062 this.clearTouchView();
15064 var rawValue = this.getRawValue();
15066 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15068 this.tickItems = [];
15070 this.store.data.each(function(d, rowIndex){
15071 var row = this.touchViewListGroup.createChild(template);
15073 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15074 row.addClass(d.data.cls);
15077 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15080 html : d.data[this.displayField]
15083 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15084 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15087 row.removeClass('selected');
15088 if(!this.multiple && this.valueField &&
15089 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15092 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15093 row.addClass('selected');
15096 if(this.multiple && this.valueField &&
15097 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15101 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15102 this.tickItems.push(d.data);
15105 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15109 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15111 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15113 if(this.modalTitle.length){
15114 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15117 var listHeight = this.touchViewListGroup.getHeight();
15121 if(firstChecked && listHeight > bodyHeight){
15122 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15127 onTouchViewLoadException : function()
15129 this.hideTouchView();
15132 onTouchViewEmptyResults : function()
15134 this.clearTouchView();
15136 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15138 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15142 clearTouchView : function()
15144 this.touchViewListGroup.dom.innerHTML = '';
15147 onTouchViewClick : function(e, el, o)
15149 e.preventDefault();
15152 var rowIndex = o.rowIndex;
15154 var r = this.store.getAt(rowIndex);
15156 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15158 if(!this.multiple){
15159 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15160 c.dom.removeAttribute('checked');
15163 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15165 this.setFromData(r.data);
15167 var close = this.closeTriggerEl();
15173 this.hideTouchView();
15175 this.fireEvent('select', this, r, rowIndex);
15180 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15181 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15182 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15186 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15187 this.addItem(r.data);
15188 this.tickItems.push(r.data);
15192 getAutoCreateNativeIOS : function()
15195 cls: 'form-group' //input-group,
15200 cls : 'roo-ios-select'
15204 combobox.name = this.name;
15207 if (this.disabled) {
15208 combobox.disabled = true;
15211 var settings = this;
15213 ['xs','sm','md','lg'].map(function(size){
15214 if (settings[size]) {
15215 cfg.cls += ' col-' + size + '-' + settings[size];
15225 initIOSView : function()
15227 this.store.on('load', this.onIOSViewLoad, this);
15232 onIOSViewLoad : function()
15234 if(this.store.getCount() < 1){
15238 this.clearIOSView();
15240 if(this.allowBlank) {
15242 var default_text = '-- SELECT --';
15244 if(this.placeholder.length){
15245 default_text = this.placeholder;
15248 if(this.emptyTitle.length){
15249 default_text += ' - ' + this.emptyTitle + ' -';
15252 var opt = this.inputEl().createChild({
15255 html : default_text
15259 o[this.valueField] = 0;
15260 o[this.displayField] = default_text;
15262 this.ios_options.push({
15269 this.store.data.each(function(d, rowIndex){
15273 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15274 html = d.data[this.displayField];
15279 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15280 value = d.data[this.valueField];
15289 if(this.value == d.data[this.valueField]){
15290 option['selected'] = true;
15293 var opt = this.inputEl().createChild(option);
15295 this.ios_options.push({
15302 this.inputEl().on('change', function(){
15303 this.fireEvent('select', this);
15308 clearIOSView: function()
15310 this.inputEl().dom.innerHTML = '';
15312 this.ios_options = [];
15315 setIOSValue: function(v)
15319 if(!this.ios_options){
15323 Roo.each(this.ios_options, function(opts){
15325 opts.el.dom.removeAttribute('selected');
15327 if(opts.data[this.valueField] != v){
15331 opts.el.dom.setAttribute('selected', true);
15337 * @cfg {Boolean} grow
15341 * @cfg {Number} growMin
15345 * @cfg {Number} growMax
15354 Roo.apply(Roo.bootstrap.ComboBox, {
15358 cls: 'modal-header',
15380 cls: 'list-group-item',
15384 cls: 'roo-combobox-list-group-item-value'
15388 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15402 listItemCheckbox : {
15404 cls: 'list-group-item',
15408 cls: 'roo-combobox-list-group-item-value'
15412 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15428 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15433 cls: 'modal-footer',
15441 cls: 'col-xs-6 text-left',
15444 cls: 'btn btn-danger roo-touch-view-cancel',
15450 cls: 'col-xs-6 text-right',
15453 cls: 'btn btn-success roo-touch-view-ok',
15464 Roo.apply(Roo.bootstrap.ComboBox, {
15466 touchViewTemplate : {
15468 cls: 'modal fade roo-combobox-touch-view',
15472 cls: 'modal-dialog',
15473 style : 'position:fixed', // we have to fix position....
15477 cls: 'modal-content',
15479 Roo.bootstrap.ComboBox.header,
15480 Roo.bootstrap.ComboBox.body,
15481 Roo.bootstrap.ComboBox.footer
15490 * Ext JS Library 1.1.1
15491 * Copyright(c) 2006-2007, Ext JS, LLC.
15493 * Originally Released Under LGPL - original licence link has changed is not relivant.
15496 * <script type="text/javascript">
15501 * @extends Roo.util.Observable
15502 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15503 * This class also supports single and multi selection modes. <br>
15504 * Create a data model bound view:
15506 var store = new Roo.data.Store(...);
15508 var view = new Roo.View({
15510 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15512 singleSelect: true,
15513 selectedClass: "ydataview-selected",
15517 // listen for node click?
15518 view.on("click", function(vw, index, node, e){
15519 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15523 dataModel.load("foobar.xml");
15525 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15527 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15528 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15530 * Note: old style constructor is still suported (container, template, config)
15533 * Create a new View
15534 * @param {Object} config The config object
15537 Roo.View = function(config, depreciated_tpl, depreciated_config){
15539 this.parent = false;
15541 if (typeof(depreciated_tpl) == 'undefined') {
15542 // new way.. - universal constructor.
15543 Roo.apply(this, config);
15544 this.el = Roo.get(this.el);
15547 this.el = Roo.get(config);
15548 this.tpl = depreciated_tpl;
15549 Roo.apply(this, depreciated_config);
15551 this.wrapEl = this.el.wrap().wrap();
15552 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15555 if(typeof(this.tpl) == "string"){
15556 this.tpl = new Roo.Template(this.tpl);
15558 // support xtype ctors..
15559 this.tpl = new Roo.factory(this.tpl, Roo);
15563 this.tpl.compile();
15568 * @event beforeclick
15569 * Fires before a click is processed. Returns false to cancel the default action.
15570 * @param {Roo.View} this
15571 * @param {Number} index The index of the target node
15572 * @param {HTMLElement} node The target node
15573 * @param {Roo.EventObject} e The raw event object
15575 "beforeclick" : true,
15578 * Fires when a template node is clicked.
15579 * @param {Roo.View} this
15580 * @param {Number} index The index of the target node
15581 * @param {HTMLElement} node The target node
15582 * @param {Roo.EventObject} e The raw event object
15587 * Fires when a template node is double clicked.
15588 * @param {Roo.View} this
15589 * @param {Number} index The index of the target node
15590 * @param {HTMLElement} node The target node
15591 * @param {Roo.EventObject} e The raw event object
15595 * @event contextmenu
15596 * Fires when a template node is right clicked.
15597 * @param {Roo.View} this
15598 * @param {Number} index The index of the target node
15599 * @param {HTMLElement} node The target node
15600 * @param {Roo.EventObject} e The raw event object
15602 "contextmenu" : true,
15604 * @event selectionchange
15605 * Fires when the selected nodes change.
15606 * @param {Roo.View} this
15607 * @param {Array} selections Array of the selected nodes
15609 "selectionchange" : true,
15612 * @event beforeselect
15613 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15614 * @param {Roo.View} this
15615 * @param {HTMLElement} node The node to be selected
15616 * @param {Array} selections Array of currently selected nodes
15618 "beforeselect" : true,
15620 * @event preparedata
15621 * Fires on every row to render, to allow you to change the data.
15622 * @param {Roo.View} this
15623 * @param {Object} data to be rendered (change this)
15625 "preparedata" : true
15633 "click": this.onClick,
15634 "dblclick": this.onDblClick,
15635 "contextmenu": this.onContextMenu,
15639 this.selections = [];
15641 this.cmp = new Roo.CompositeElementLite([]);
15643 this.store = Roo.factory(this.store, Roo.data);
15644 this.setStore(this.store, true);
15647 if ( this.footer && this.footer.xtype) {
15649 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15651 this.footer.dataSource = this.store;
15652 this.footer.container = fctr;
15653 this.footer = Roo.factory(this.footer, Roo);
15654 fctr.insertFirst(this.el);
15656 // this is a bit insane - as the paging toolbar seems to detach the el..
15657 // dom.parentNode.parentNode.parentNode
15658 // they get detached?
15662 Roo.View.superclass.constructor.call(this);
15667 Roo.extend(Roo.View, Roo.util.Observable, {
15670 * @cfg {Roo.data.Store} store Data store to load data from.
15675 * @cfg {String|Roo.Element} el The container element.
15680 * @cfg {String|Roo.Template} tpl The template used by this View
15684 * @cfg {String} dataName the named area of the template to use as the data area
15685 * Works with domtemplates roo-name="name"
15689 * @cfg {String} selectedClass The css class to add to selected nodes
15691 selectedClass : "x-view-selected",
15693 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15698 * @cfg {String} text to display on mask (default Loading)
15702 * @cfg {Boolean} multiSelect Allow multiple selection
15704 multiSelect : false,
15706 * @cfg {Boolean} singleSelect Allow single selection
15708 singleSelect: false,
15711 * @cfg {Boolean} toggleSelect - selecting
15713 toggleSelect : false,
15716 * @cfg {Boolean} tickable - selecting
15721 * Returns the element this view is bound to.
15722 * @return {Roo.Element}
15724 getEl : function(){
15725 return this.wrapEl;
15731 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15733 refresh : function(){
15734 //Roo.log('refresh');
15737 // if we are using something like 'domtemplate', then
15738 // the what gets used is:
15739 // t.applySubtemplate(NAME, data, wrapping data..)
15740 // the outer template then get' applied with
15741 // the store 'extra data'
15742 // and the body get's added to the
15743 // roo-name="data" node?
15744 // <span class='roo-tpl-{name}'></span> ?????
15748 this.clearSelections();
15749 this.el.update("");
15751 var records = this.store.getRange();
15752 if(records.length < 1) {
15754 // is this valid?? = should it render a template??
15756 this.el.update(this.emptyText);
15760 if (this.dataName) {
15761 this.el.update(t.apply(this.store.meta)); //????
15762 el = this.el.child('.roo-tpl-' + this.dataName);
15765 for(var i = 0, len = records.length; i < len; i++){
15766 var data = this.prepareData(records[i].data, i, records[i]);
15767 this.fireEvent("preparedata", this, data, i, records[i]);
15769 var d = Roo.apply({}, data);
15772 Roo.apply(d, {'roo-id' : Roo.id()});
15776 Roo.each(this.parent.item, function(item){
15777 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15780 Roo.apply(d, {'roo-data-checked' : 'checked'});
15784 html[html.length] = Roo.util.Format.trim(
15786 t.applySubtemplate(this.dataName, d, this.store.meta) :
15793 el.update(html.join(""));
15794 this.nodes = el.dom.childNodes;
15795 this.updateIndexes(0);
15800 * Function to override to reformat the data that is sent to
15801 * the template for each node.
15802 * DEPRICATED - use the preparedata event handler.
15803 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15804 * a JSON object for an UpdateManager bound view).
15806 prepareData : function(data, index, record)
15808 this.fireEvent("preparedata", this, data, index, record);
15812 onUpdate : function(ds, record){
15813 // Roo.log('on update');
15814 this.clearSelections();
15815 var index = this.store.indexOf(record);
15816 var n = this.nodes[index];
15817 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15818 n.parentNode.removeChild(n);
15819 this.updateIndexes(index, index);
15825 onAdd : function(ds, records, index)
15827 //Roo.log(['on Add', ds, records, index] );
15828 this.clearSelections();
15829 if(this.nodes.length == 0){
15833 var n = this.nodes[index];
15834 for(var i = 0, len = records.length; i < len; i++){
15835 var d = this.prepareData(records[i].data, i, records[i]);
15837 this.tpl.insertBefore(n, d);
15840 this.tpl.append(this.el, d);
15843 this.updateIndexes(index);
15846 onRemove : function(ds, record, index){
15847 // Roo.log('onRemove');
15848 this.clearSelections();
15849 var el = this.dataName ?
15850 this.el.child('.roo-tpl-' + this.dataName) :
15853 el.dom.removeChild(this.nodes[index]);
15854 this.updateIndexes(index);
15858 * Refresh an individual node.
15859 * @param {Number} index
15861 refreshNode : function(index){
15862 this.onUpdate(this.store, this.store.getAt(index));
15865 updateIndexes : function(startIndex, endIndex){
15866 var ns = this.nodes;
15867 startIndex = startIndex || 0;
15868 endIndex = endIndex || ns.length - 1;
15869 for(var i = startIndex; i <= endIndex; i++){
15870 ns[i].nodeIndex = i;
15875 * Changes the data store this view uses and refresh the view.
15876 * @param {Store} store
15878 setStore : function(store, initial){
15879 if(!initial && this.store){
15880 this.store.un("datachanged", this.refresh);
15881 this.store.un("add", this.onAdd);
15882 this.store.un("remove", this.onRemove);
15883 this.store.un("update", this.onUpdate);
15884 this.store.un("clear", this.refresh);
15885 this.store.un("beforeload", this.onBeforeLoad);
15886 this.store.un("load", this.onLoad);
15887 this.store.un("loadexception", this.onLoad);
15891 store.on("datachanged", this.refresh, this);
15892 store.on("add", this.onAdd, this);
15893 store.on("remove", this.onRemove, this);
15894 store.on("update", this.onUpdate, this);
15895 store.on("clear", this.refresh, this);
15896 store.on("beforeload", this.onBeforeLoad, this);
15897 store.on("load", this.onLoad, this);
15898 store.on("loadexception", this.onLoad, this);
15906 * onbeforeLoad - masks the loading area.
15909 onBeforeLoad : function(store,opts)
15911 //Roo.log('onBeforeLoad');
15913 this.el.update("");
15915 this.el.mask(this.mask ? this.mask : "Loading" );
15917 onLoad : function ()
15924 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15925 * @param {HTMLElement} node
15926 * @return {HTMLElement} The template node
15928 findItemFromChild : function(node){
15929 var el = this.dataName ?
15930 this.el.child('.roo-tpl-' + this.dataName,true) :
15933 if(!node || node.parentNode == el){
15936 var p = node.parentNode;
15937 while(p && p != el){
15938 if(p.parentNode == el){
15947 onClick : function(e){
15948 var item = this.findItemFromChild(e.getTarget());
15950 var index = this.indexOf(item);
15951 if(this.onItemClick(item, index, e) !== false){
15952 this.fireEvent("click", this, index, item, e);
15955 this.clearSelections();
15960 onContextMenu : function(e){
15961 var item = this.findItemFromChild(e.getTarget());
15963 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15968 onDblClick : function(e){
15969 var item = this.findItemFromChild(e.getTarget());
15971 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15975 onItemClick : function(item, index, e)
15977 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15980 if (this.toggleSelect) {
15981 var m = this.isSelected(item) ? 'unselect' : 'select';
15984 _t[m](item, true, false);
15987 if(this.multiSelect || this.singleSelect){
15988 if(this.multiSelect && e.shiftKey && this.lastSelection){
15989 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15991 this.select(item, this.multiSelect && e.ctrlKey);
15992 this.lastSelection = item;
15995 if(!this.tickable){
15996 e.preventDefault();
16004 * Get the number of selected nodes.
16007 getSelectionCount : function(){
16008 return this.selections.length;
16012 * Get the currently selected nodes.
16013 * @return {Array} An array of HTMLElements
16015 getSelectedNodes : function(){
16016 return this.selections;
16020 * Get the indexes of the selected nodes.
16023 getSelectedIndexes : function(){
16024 var indexes = [], s = this.selections;
16025 for(var i = 0, len = s.length; i < len; i++){
16026 indexes.push(s[i].nodeIndex);
16032 * Clear all selections
16033 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16035 clearSelections : function(suppressEvent){
16036 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16037 this.cmp.elements = this.selections;
16038 this.cmp.removeClass(this.selectedClass);
16039 this.selections = [];
16040 if(!suppressEvent){
16041 this.fireEvent("selectionchange", this, this.selections);
16047 * Returns true if the passed node is selected
16048 * @param {HTMLElement/Number} node The node or node index
16049 * @return {Boolean}
16051 isSelected : function(node){
16052 var s = this.selections;
16056 node = this.getNode(node);
16057 return s.indexOf(node) !== -1;
16062 * @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
16063 * @param {Boolean} keepExisting (optional) true to keep existing selections
16064 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16066 select : function(nodeInfo, keepExisting, suppressEvent){
16067 if(nodeInfo instanceof Array){
16069 this.clearSelections(true);
16071 for(var i = 0, len = nodeInfo.length; i < len; i++){
16072 this.select(nodeInfo[i], true, true);
16076 var node = this.getNode(nodeInfo);
16077 if(!node || this.isSelected(node)){
16078 return; // already selected.
16081 this.clearSelections(true);
16084 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16085 Roo.fly(node).addClass(this.selectedClass);
16086 this.selections.push(node);
16087 if(!suppressEvent){
16088 this.fireEvent("selectionchange", this, this.selections);
16096 * @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
16097 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16098 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16100 unselect : function(nodeInfo, keepExisting, suppressEvent)
16102 if(nodeInfo instanceof Array){
16103 Roo.each(this.selections, function(s) {
16104 this.unselect(s, nodeInfo);
16108 var node = this.getNode(nodeInfo);
16109 if(!node || !this.isSelected(node)){
16110 //Roo.log("not selected");
16111 return; // not selected.
16115 Roo.each(this.selections, function(s) {
16117 Roo.fly(node).removeClass(this.selectedClass);
16124 this.selections= ns;
16125 this.fireEvent("selectionchange", this, this.selections);
16129 * Gets a template node.
16130 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16131 * @return {HTMLElement} The node or null if it wasn't found
16133 getNode : function(nodeInfo){
16134 if(typeof nodeInfo == "string"){
16135 return document.getElementById(nodeInfo);
16136 }else if(typeof nodeInfo == "number"){
16137 return this.nodes[nodeInfo];
16143 * Gets a range template nodes.
16144 * @param {Number} startIndex
16145 * @param {Number} endIndex
16146 * @return {Array} An array of nodes
16148 getNodes : function(start, end){
16149 var ns = this.nodes;
16150 start = start || 0;
16151 end = typeof end == "undefined" ? ns.length - 1 : end;
16154 for(var i = start; i <= end; i++){
16158 for(var i = start; i >= end; i--){
16166 * Finds the index of the passed node
16167 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16168 * @return {Number} The index of the node or -1
16170 indexOf : function(node){
16171 node = this.getNode(node);
16172 if(typeof node.nodeIndex == "number"){
16173 return node.nodeIndex;
16175 var ns = this.nodes;
16176 for(var i = 0, len = ns.length; i < len; i++){
16187 * based on jquery fullcalendar
16191 Roo.bootstrap = Roo.bootstrap || {};
16193 * @class Roo.bootstrap.Calendar
16194 * @extends Roo.bootstrap.Component
16195 * Bootstrap Calendar class
16196 * @cfg {Boolean} loadMask (true|false) default false
16197 * @cfg {Object} header generate the user specific header of the calendar, default false
16200 * Create a new Container
16201 * @param {Object} config The config object
16206 Roo.bootstrap.Calendar = function(config){
16207 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16211 * Fires when a date is selected
16212 * @param {DatePicker} this
16213 * @param {Date} date The selected date
16217 * @event monthchange
16218 * Fires when the displayed month changes
16219 * @param {DatePicker} this
16220 * @param {Date} date The selected month
16222 'monthchange': true,
16224 * @event evententer
16225 * Fires when mouse over an event
16226 * @param {Calendar} this
16227 * @param {event} Event
16229 'evententer': true,
16231 * @event eventleave
16232 * Fires when the mouse leaves an
16233 * @param {Calendar} this
16236 'eventleave': true,
16238 * @event eventclick
16239 * Fires when the mouse click an
16240 * @param {Calendar} this
16249 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16252 * @cfg {Number} startDay
16253 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16261 getAutoCreate : function(){
16264 var fc_button = function(name, corner, style, content ) {
16265 return Roo.apply({},{
16267 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16269 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16272 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16283 style : 'width:100%',
16290 cls : 'fc-header-left',
16292 fc_button('prev', 'left', 'arrow', '‹' ),
16293 fc_button('next', 'right', 'arrow', '›' ),
16294 { tag: 'span', cls: 'fc-header-space' },
16295 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16303 cls : 'fc-header-center',
16307 cls: 'fc-header-title',
16310 html : 'month / year'
16318 cls : 'fc-header-right',
16320 /* fc_button('month', 'left', '', 'month' ),
16321 fc_button('week', '', '', 'week' ),
16322 fc_button('day', 'right', '', 'day' )
16334 header = this.header;
16337 var cal_heads = function() {
16339 // fixme - handle this.
16341 for (var i =0; i < Date.dayNames.length; i++) {
16342 var d = Date.dayNames[i];
16345 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16346 html : d.substring(0,3)
16350 ret[0].cls += ' fc-first';
16351 ret[6].cls += ' fc-last';
16354 var cal_cell = function(n) {
16357 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16362 cls: 'fc-day-number',
16366 cls: 'fc-day-content',
16370 style: 'position: relative;' // height: 17px;
16382 var cal_rows = function() {
16385 for (var r = 0; r < 6; r++) {
16392 for (var i =0; i < Date.dayNames.length; i++) {
16393 var d = Date.dayNames[i];
16394 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16397 row.cn[0].cls+=' fc-first';
16398 row.cn[0].cn[0].style = 'min-height:90px';
16399 row.cn[6].cls+=' fc-last';
16403 ret[0].cls += ' fc-first';
16404 ret[4].cls += ' fc-prev-last';
16405 ret[5].cls += ' fc-last';
16412 cls: 'fc-border-separate',
16413 style : 'width:100%',
16421 cls : 'fc-first fc-last',
16439 cls : 'fc-content',
16440 style : "position: relative;",
16443 cls : 'fc-view fc-view-month fc-grid',
16444 style : 'position: relative',
16445 unselectable : 'on',
16448 cls : 'fc-event-container',
16449 style : 'position:absolute;z-index:8;top:0;left:0;'
16467 initEvents : function()
16470 throw "can not find store for calendar";
16476 style: "text-align:center",
16480 style: "background-color:white;width:50%;margin:250 auto",
16484 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16495 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16497 var size = this.el.select('.fc-content', true).first().getSize();
16498 this.maskEl.setSize(size.width, size.height);
16499 this.maskEl.enableDisplayMode("block");
16500 if(!this.loadMask){
16501 this.maskEl.hide();
16504 this.store = Roo.factory(this.store, Roo.data);
16505 this.store.on('load', this.onLoad, this);
16506 this.store.on('beforeload', this.onBeforeLoad, this);
16510 this.cells = this.el.select('.fc-day',true);
16511 //Roo.log(this.cells);
16512 this.textNodes = this.el.query('.fc-day-number');
16513 this.cells.addClassOnOver('fc-state-hover');
16515 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16516 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16517 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16518 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16520 this.on('monthchange', this.onMonthChange, this);
16522 this.update(new Date().clearTime());
16525 resize : function() {
16526 var sz = this.el.getSize();
16528 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16529 this.el.select('.fc-day-content div',true).setHeight(34);
16534 showPrevMonth : function(e){
16535 this.update(this.activeDate.add("mo", -1));
16537 showToday : function(e){
16538 this.update(new Date().clearTime());
16541 showNextMonth : function(e){
16542 this.update(this.activeDate.add("mo", 1));
16546 showPrevYear : function(){
16547 this.update(this.activeDate.add("y", -1));
16551 showNextYear : function(){
16552 this.update(this.activeDate.add("y", 1));
16557 update : function(date)
16559 var vd = this.activeDate;
16560 this.activeDate = date;
16561 // if(vd && this.el){
16562 // var t = date.getTime();
16563 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16564 // Roo.log('using add remove');
16566 // this.fireEvent('monthchange', this, date);
16568 // this.cells.removeClass("fc-state-highlight");
16569 // this.cells.each(function(c){
16570 // if(c.dateValue == t){
16571 // c.addClass("fc-state-highlight");
16572 // setTimeout(function(){
16573 // try{c.dom.firstChild.focus();}catch(e){}
16583 var days = date.getDaysInMonth();
16585 var firstOfMonth = date.getFirstDateOfMonth();
16586 var startingPos = firstOfMonth.getDay()-this.startDay;
16588 if(startingPos < this.startDay){
16592 var pm = date.add(Date.MONTH, -1);
16593 var prevStart = pm.getDaysInMonth()-startingPos;
16595 this.cells = this.el.select('.fc-day',true);
16596 this.textNodes = this.el.query('.fc-day-number');
16597 this.cells.addClassOnOver('fc-state-hover');
16599 var cells = this.cells.elements;
16600 var textEls = this.textNodes;
16602 Roo.each(cells, function(cell){
16603 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16606 days += startingPos;
16608 // convert everything to numbers so it's fast
16609 var day = 86400000;
16610 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16613 //Roo.log(prevStart);
16615 var today = new Date().clearTime().getTime();
16616 var sel = date.clearTime().getTime();
16617 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16618 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16619 var ddMatch = this.disabledDatesRE;
16620 var ddText = this.disabledDatesText;
16621 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16622 var ddaysText = this.disabledDaysText;
16623 var format = this.format;
16625 var setCellClass = function(cal, cell){
16629 //Roo.log('set Cell Class');
16631 var t = d.getTime();
16635 cell.dateValue = t;
16637 cell.className += " fc-today";
16638 cell.className += " fc-state-highlight";
16639 cell.title = cal.todayText;
16642 // disable highlight in other month..
16643 //cell.className += " fc-state-highlight";
16648 cell.className = " fc-state-disabled";
16649 cell.title = cal.minText;
16653 cell.className = " fc-state-disabled";
16654 cell.title = cal.maxText;
16658 if(ddays.indexOf(d.getDay()) != -1){
16659 cell.title = ddaysText;
16660 cell.className = " fc-state-disabled";
16663 if(ddMatch && format){
16664 var fvalue = d.dateFormat(format);
16665 if(ddMatch.test(fvalue)){
16666 cell.title = ddText.replace("%0", fvalue);
16667 cell.className = " fc-state-disabled";
16671 if (!cell.initialClassName) {
16672 cell.initialClassName = cell.dom.className;
16675 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16680 for(; i < startingPos; i++) {
16681 textEls[i].innerHTML = (++prevStart);
16682 d.setDate(d.getDate()+1);
16684 cells[i].className = "fc-past fc-other-month";
16685 setCellClass(this, cells[i]);
16690 for(; i < days; i++){
16691 intDay = i - startingPos + 1;
16692 textEls[i].innerHTML = (intDay);
16693 d.setDate(d.getDate()+1);
16695 cells[i].className = ''; // "x-date-active";
16696 setCellClass(this, cells[i]);
16700 for(; i < 42; i++) {
16701 textEls[i].innerHTML = (++extraDays);
16702 d.setDate(d.getDate()+1);
16704 cells[i].className = "fc-future fc-other-month";
16705 setCellClass(this, cells[i]);
16708 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16710 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16712 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16713 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16715 if(totalRows != 6){
16716 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16717 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16720 this.fireEvent('monthchange', this, date);
16724 if(!this.internalRender){
16725 var main = this.el.dom.firstChild;
16726 var w = main.offsetWidth;
16727 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16728 Roo.fly(main).setWidth(w);
16729 this.internalRender = true;
16730 // opera does not respect the auto grow header center column
16731 // then, after it gets a width opera refuses to recalculate
16732 // without a second pass
16733 if(Roo.isOpera && !this.secondPass){
16734 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16735 this.secondPass = true;
16736 this.update.defer(10, this, [date]);
16743 findCell : function(dt) {
16744 dt = dt.clearTime().getTime();
16746 this.cells.each(function(c){
16747 //Roo.log("check " +c.dateValue + '?=' + dt);
16748 if(c.dateValue == dt){
16758 findCells : function(ev) {
16759 var s = ev.start.clone().clearTime().getTime();
16761 var e= ev.end.clone().clearTime().getTime();
16764 this.cells.each(function(c){
16765 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16767 if(c.dateValue > e){
16770 if(c.dateValue < s){
16779 // findBestRow: function(cells)
16783 // for (var i =0 ; i < cells.length;i++) {
16784 // ret = Math.max(cells[i].rows || 0,ret);
16791 addItem : function(ev)
16793 // look for vertical location slot in
16794 var cells = this.findCells(ev);
16796 // ev.row = this.findBestRow(cells);
16798 // work out the location.
16802 for(var i =0; i < cells.length; i++) {
16804 cells[i].row = cells[0].row;
16807 cells[i].row = cells[i].row + 1;
16817 if (crow.start.getY() == cells[i].getY()) {
16819 crow.end = cells[i];
16836 cells[0].events.push(ev);
16838 this.calevents.push(ev);
16841 clearEvents: function() {
16843 if(!this.calevents){
16847 Roo.each(this.cells.elements, function(c){
16853 Roo.each(this.calevents, function(e) {
16854 Roo.each(e.els, function(el) {
16855 el.un('mouseenter' ,this.onEventEnter, this);
16856 el.un('mouseleave' ,this.onEventLeave, this);
16861 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16867 renderEvents: function()
16871 this.cells.each(function(c) {
16880 if(c.row != c.events.length){
16881 r = 4 - (4 - (c.row - c.events.length));
16884 c.events = ev.slice(0, r);
16885 c.more = ev.slice(r);
16887 if(c.more.length && c.more.length == 1){
16888 c.events.push(c.more.pop());
16891 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16895 this.cells.each(function(c) {
16897 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16900 for (var e = 0; e < c.events.length; e++){
16901 var ev = c.events[e];
16902 var rows = ev.rows;
16904 for(var i = 0; i < rows.length; i++) {
16906 // how many rows should it span..
16909 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16910 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16912 unselectable : "on",
16915 cls: 'fc-event-inner',
16919 // cls: 'fc-event-time',
16920 // html : cells.length > 1 ? '' : ev.time
16924 cls: 'fc-event-title',
16925 html : String.format('{0}', ev.title)
16932 cls: 'ui-resizable-handle ui-resizable-e',
16933 html : '  '
16940 cfg.cls += ' fc-event-start';
16942 if ((i+1) == rows.length) {
16943 cfg.cls += ' fc-event-end';
16946 var ctr = _this.el.select('.fc-event-container',true).first();
16947 var cg = ctr.createChild(cfg);
16949 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16950 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16952 var r = (c.more.length) ? 1 : 0;
16953 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16954 cg.setWidth(ebox.right - sbox.x -2);
16956 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16957 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16958 cg.on('click', _this.onEventClick, _this, ev);
16969 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16970 style : 'position: absolute',
16971 unselectable : "on",
16974 cls: 'fc-event-inner',
16978 cls: 'fc-event-title',
16986 cls: 'ui-resizable-handle ui-resizable-e',
16987 html : '  '
16993 var ctr = _this.el.select('.fc-event-container',true).first();
16994 var cg = ctr.createChild(cfg);
16996 var sbox = c.select('.fc-day-content',true).first().getBox();
16997 var ebox = c.select('.fc-day-content',true).first().getBox();
16999 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17000 cg.setWidth(ebox.right - sbox.x -2);
17002 cg.on('click', _this.onMoreEventClick, _this, c.more);
17012 onEventEnter: function (e, el,event,d) {
17013 this.fireEvent('evententer', this, el, event);
17016 onEventLeave: function (e, el,event,d) {
17017 this.fireEvent('eventleave', this, el, event);
17020 onEventClick: function (e, el,event,d) {
17021 this.fireEvent('eventclick', this, el, event);
17024 onMonthChange: function () {
17028 onMoreEventClick: function(e, el, more)
17032 this.calpopover.placement = 'right';
17033 this.calpopover.setTitle('More');
17035 this.calpopover.setContent('');
17037 var ctr = this.calpopover.el.select('.popover-content', true).first();
17039 Roo.each(more, function(m){
17041 cls : 'fc-event-hori fc-event-draggable',
17044 var cg = ctr.createChild(cfg);
17046 cg.on('click', _this.onEventClick, _this, m);
17049 this.calpopover.show(el);
17054 onLoad: function ()
17056 this.calevents = [];
17059 if(this.store.getCount() > 0){
17060 this.store.data.each(function(d){
17063 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17064 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17065 time : d.data.start_time,
17066 title : d.data.title,
17067 description : d.data.description,
17068 venue : d.data.venue
17073 this.renderEvents();
17075 if(this.calevents.length && this.loadMask){
17076 this.maskEl.hide();
17080 onBeforeLoad: function()
17082 this.clearEvents();
17084 this.maskEl.show();
17098 * @class Roo.bootstrap.Popover
17099 * @extends Roo.bootstrap.Component
17100 * Bootstrap Popover class
17101 * @cfg {String} html contents of the popover (or false to use children..)
17102 * @cfg {String} title of popover (or false to hide)
17103 * @cfg {String} placement how it is placed
17104 * @cfg {String} trigger click || hover (or false to trigger manually)
17105 * @cfg {String} over what (parent or false to trigger manually.)
17106 * @cfg {Number} delay - delay before showing
17109 * Create a new Popover
17110 * @param {Object} config The config object
17113 Roo.bootstrap.Popover = function(config){
17114 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17120 * After the popover show
17122 * @param {Roo.bootstrap.Popover} this
17127 * After the popover hide
17129 * @param {Roo.bootstrap.Popover} this
17135 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17137 title: 'Fill in a title',
17140 placement : 'right',
17141 trigger : 'hover', // hover
17147 can_build_overlaid : false,
17149 getChildContainer : function()
17151 return this.el.select('.popover-content',true).first();
17154 getAutoCreate : function(){
17157 cls : 'popover roo-dynamic',
17158 style: 'display:block',
17164 cls : 'popover-inner',
17168 cls: 'popover-title',
17172 cls : 'popover-content',
17183 setTitle: function(str)
17186 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17188 setContent: function(str)
17191 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17193 // as it get's added to the bottom of the page.
17194 onRender : function(ct, position)
17196 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17198 var cfg = Roo.apply({}, this.getAutoCreate());
17202 cfg.cls += ' ' + this.cls;
17205 cfg.style = this.style;
17207 //Roo.log("adding to ");
17208 this.el = Roo.get(document.body).createChild(cfg, position);
17209 // Roo.log(this.el);
17214 initEvents : function()
17216 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17217 this.el.enableDisplayMode('block');
17219 if (this.over === false) {
17222 if (this.triggers === false) {
17225 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17226 var triggers = this.trigger ? this.trigger.split(' ') : [];
17227 Roo.each(triggers, function(trigger) {
17229 if (trigger == 'click') {
17230 on_el.on('click', this.toggle, this);
17231 } else if (trigger != 'manual') {
17232 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17233 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17235 on_el.on(eventIn ,this.enter, this);
17236 on_el.on(eventOut, this.leave, this);
17247 toggle : function () {
17248 this.hoverState == 'in' ? this.leave() : this.enter();
17251 enter : function () {
17253 clearTimeout(this.timeout);
17255 this.hoverState = 'in';
17257 if (!this.delay || !this.delay.show) {
17262 this.timeout = setTimeout(function () {
17263 if (_t.hoverState == 'in') {
17266 }, this.delay.show)
17269 leave : function() {
17270 clearTimeout(this.timeout);
17272 this.hoverState = 'out';
17274 if (!this.delay || !this.delay.hide) {
17279 this.timeout = setTimeout(function () {
17280 if (_t.hoverState == 'out') {
17283 }, this.delay.hide)
17286 show : function (on_el)
17289 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17293 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17294 if (this.html !== false) {
17295 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17297 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17298 if (!this.title.length) {
17299 this.el.select('.popover-title',true).hide();
17302 var placement = typeof this.placement == 'function' ?
17303 this.placement.call(this, this.el, on_el) :
17306 var autoToken = /\s?auto?\s?/i;
17307 var autoPlace = autoToken.test(placement);
17309 placement = placement.replace(autoToken, '') || 'top';
17313 //this.el.setXY([0,0]);
17315 this.el.dom.style.display='block';
17316 this.el.addClass(placement);
17318 //this.el.appendTo(on_el);
17320 var p = this.getPosition();
17321 var box = this.el.getBox();
17326 var align = Roo.bootstrap.Popover.alignment[placement];
17329 this.el.alignTo(on_el, align[0],align[1]);
17330 //var arrow = this.el.select('.arrow',true).first();
17331 //arrow.set(align[2],
17333 this.el.addClass('in');
17336 if (this.el.hasClass('fade')) {
17340 this.hoverState = 'in';
17342 this.fireEvent('show', this);
17347 this.el.setXY([0,0]);
17348 this.el.removeClass('in');
17350 this.hoverState = null;
17352 this.fireEvent('hide', this);
17357 Roo.bootstrap.Popover.alignment = {
17358 'left' : ['r-l', [-10,0], 'right'],
17359 'right' : ['l-r', [10,0], 'left'],
17360 'bottom' : ['t-b', [0,10], 'top'],
17361 'top' : [ 'b-t', [0,-10], 'bottom']
17372 * @class Roo.bootstrap.Progress
17373 * @extends Roo.bootstrap.Component
17374 * Bootstrap Progress class
17375 * @cfg {Boolean} striped striped of the progress bar
17376 * @cfg {Boolean} active animated of the progress bar
17380 * Create a new Progress
17381 * @param {Object} config The config object
17384 Roo.bootstrap.Progress = function(config){
17385 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17388 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17393 getAutoCreate : function(){
17401 cfg.cls += ' progress-striped';
17405 cfg.cls += ' active';
17424 * @class Roo.bootstrap.ProgressBar
17425 * @extends Roo.bootstrap.Component
17426 * Bootstrap ProgressBar class
17427 * @cfg {Number} aria_valuenow aria-value now
17428 * @cfg {Number} aria_valuemin aria-value min
17429 * @cfg {Number} aria_valuemax aria-value max
17430 * @cfg {String} label label for the progress bar
17431 * @cfg {String} panel (success | info | warning | danger )
17432 * @cfg {String} role role of the progress bar
17433 * @cfg {String} sr_only text
17437 * Create a new ProgressBar
17438 * @param {Object} config The config object
17441 Roo.bootstrap.ProgressBar = function(config){
17442 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17445 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17449 aria_valuemax : 100,
17455 getAutoCreate : function()
17460 cls: 'progress-bar',
17461 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17473 cfg.role = this.role;
17476 if(this.aria_valuenow){
17477 cfg['aria-valuenow'] = this.aria_valuenow;
17480 if(this.aria_valuemin){
17481 cfg['aria-valuemin'] = this.aria_valuemin;
17484 if(this.aria_valuemax){
17485 cfg['aria-valuemax'] = this.aria_valuemax;
17488 if(this.label && !this.sr_only){
17489 cfg.html = this.label;
17493 cfg.cls += ' progress-bar-' + this.panel;
17499 update : function(aria_valuenow)
17501 this.aria_valuenow = aria_valuenow;
17503 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17518 * @class Roo.bootstrap.TabGroup
17519 * @extends Roo.bootstrap.Column
17520 * Bootstrap Column class
17521 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17522 * @cfg {Boolean} carousel true to make the group behave like a carousel
17523 * @cfg {Boolean} bullets show bullets for the panels
17524 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17525 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17526 * @cfg {Boolean} showarrow (true|false) show arrow default true
17529 * Create a new TabGroup
17530 * @param {Object} config The config object
17533 Roo.bootstrap.TabGroup = function(config){
17534 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17536 this.navId = Roo.id();
17539 Roo.bootstrap.TabGroup.register(this);
17543 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17546 transition : false,
17551 slideOnTouch : false,
17554 getAutoCreate : function()
17556 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17558 cfg.cls += ' tab-content';
17560 if (this.carousel) {
17561 cfg.cls += ' carousel slide';
17564 cls : 'carousel-inner',
17568 if(this.bullets && !Roo.isTouch){
17571 cls : 'carousel-bullets',
17575 if(this.bullets_cls){
17576 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17583 cfg.cn[0].cn.push(bullets);
17586 if(this.showarrow){
17587 cfg.cn[0].cn.push({
17589 class : 'carousel-arrow',
17593 class : 'carousel-prev',
17597 class : 'fa fa-chevron-left'
17603 class : 'carousel-next',
17607 class : 'fa fa-chevron-right'
17620 initEvents: function()
17622 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17623 // this.el.on("touchstart", this.onTouchStart, this);
17626 if(this.autoslide){
17629 this.slideFn = window.setInterval(function() {
17630 _this.showPanelNext();
17634 if(this.showarrow){
17635 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17636 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17642 // onTouchStart : function(e, el, o)
17644 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17648 // this.showPanelNext();
17652 getChildContainer : function()
17654 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17658 * register a Navigation item
17659 * @param {Roo.bootstrap.NavItem} the navitem to add
17661 register : function(item)
17663 this.tabs.push( item);
17664 item.navId = this.navId; // not really needed..
17669 getActivePanel : function()
17672 Roo.each(this.tabs, function(t) {
17682 getPanelByName : function(n)
17685 Roo.each(this.tabs, function(t) {
17686 if (t.tabId == n) {
17694 indexOfPanel : function(p)
17697 Roo.each(this.tabs, function(t,i) {
17698 if (t.tabId == p.tabId) {
17707 * show a specific panel
17708 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17709 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17711 showPanel : function (pan)
17713 if(this.transition || typeof(pan) == 'undefined'){
17714 Roo.log("waiting for the transitionend");
17718 if (typeof(pan) == 'number') {
17719 pan = this.tabs[pan];
17722 if (typeof(pan) == 'string') {
17723 pan = this.getPanelByName(pan);
17726 var cur = this.getActivePanel();
17729 Roo.log('pan or acitve pan is undefined');
17733 if (pan.tabId == this.getActivePanel().tabId) {
17737 if (false === cur.fireEvent('beforedeactivate')) {
17741 if(this.bullets > 0 && !Roo.isTouch){
17742 this.setActiveBullet(this.indexOfPanel(pan));
17745 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17747 this.transition = true;
17748 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17749 var lr = dir == 'next' ? 'left' : 'right';
17750 pan.el.addClass(dir); // or prev
17751 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17752 cur.el.addClass(lr); // or right
17753 pan.el.addClass(lr);
17756 cur.el.on('transitionend', function() {
17757 Roo.log("trans end?");
17759 pan.el.removeClass([lr,dir]);
17760 pan.setActive(true);
17762 cur.el.removeClass([lr]);
17763 cur.setActive(false);
17765 _this.transition = false;
17767 }, this, { single: true } );
17772 cur.setActive(false);
17773 pan.setActive(true);
17778 showPanelNext : function()
17780 var i = this.indexOfPanel(this.getActivePanel());
17782 if (i >= this.tabs.length - 1 && !this.autoslide) {
17786 if (i >= this.tabs.length - 1 && this.autoslide) {
17790 this.showPanel(this.tabs[i+1]);
17793 showPanelPrev : function()
17795 var i = this.indexOfPanel(this.getActivePanel());
17797 if (i < 1 && !this.autoslide) {
17801 if (i < 1 && this.autoslide) {
17802 i = this.tabs.length;
17805 this.showPanel(this.tabs[i-1]);
17809 addBullet: function()
17811 if(!this.bullets || Roo.isTouch){
17814 var ctr = this.el.select('.carousel-bullets',true).first();
17815 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17816 var bullet = ctr.createChild({
17817 cls : 'bullet bullet-' + i
17818 },ctr.dom.lastChild);
17823 bullet.on('click', (function(e, el, o, ii, t){
17825 e.preventDefault();
17827 this.showPanel(ii);
17829 if(this.autoslide && this.slideFn){
17830 clearInterval(this.slideFn);
17831 this.slideFn = window.setInterval(function() {
17832 _this.showPanelNext();
17836 }).createDelegate(this, [i, bullet], true));
17841 setActiveBullet : function(i)
17847 Roo.each(this.el.select('.bullet', true).elements, function(el){
17848 el.removeClass('selected');
17851 var bullet = this.el.select('.bullet-' + i, true).first();
17857 bullet.addClass('selected');
17868 Roo.apply(Roo.bootstrap.TabGroup, {
17872 * register a Navigation Group
17873 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17875 register : function(navgrp)
17877 this.groups[navgrp.navId] = navgrp;
17881 * fetch a Navigation Group based on the navigation ID
17882 * if one does not exist , it will get created.
17883 * @param {string} the navgroup to add
17884 * @returns {Roo.bootstrap.NavGroup} the navgroup
17886 get: function(navId) {
17887 if (typeof(this.groups[navId]) == 'undefined') {
17888 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17890 return this.groups[navId] ;
17905 * @class Roo.bootstrap.TabPanel
17906 * @extends Roo.bootstrap.Component
17907 * Bootstrap TabPanel class
17908 * @cfg {Boolean} active panel active
17909 * @cfg {String} html panel content
17910 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17911 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17912 * @cfg {String} href click to link..
17916 * Create a new TabPanel
17917 * @param {Object} config The config object
17920 Roo.bootstrap.TabPanel = function(config){
17921 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17925 * Fires when the active status changes
17926 * @param {Roo.bootstrap.TabPanel} this
17927 * @param {Boolean} state the new state
17932 * @event beforedeactivate
17933 * Fires before a tab is de-activated - can be used to do validation on a form.
17934 * @param {Roo.bootstrap.TabPanel} this
17935 * @return {Boolean} false if there is an error
17938 'beforedeactivate': true
17941 this.tabId = this.tabId || Roo.id();
17945 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17953 getAutoCreate : function(){
17956 // item is needed for carousel - not sure if it has any effect otherwise
17957 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17958 html: this.html || ''
17962 cfg.cls += ' active';
17966 cfg.tabId = this.tabId;
17973 initEvents: function()
17975 var p = this.parent();
17977 this.navId = this.navId || p.navId;
17979 if (typeof(this.navId) != 'undefined') {
17980 // not really needed.. but just in case.. parent should be a NavGroup.
17981 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17985 var i = tg.tabs.length - 1;
17987 if(this.active && tg.bullets > 0 && i < tg.bullets){
17988 tg.setActiveBullet(i);
17992 this.el.on('click', this.onClick, this);
17995 this.el.on("touchstart", this.onTouchStart, this);
17996 this.el.on("touchmove", this.onTouchMove, this);
17997 this.el.on("touchend", this.onTouchEnd, this);
18002 onRender : function(ct, position)
18004 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18007 setActive : function(state)
18009 Roo.log("panel - set active " + this.tabId + "=" + state);
18011 this.active = state;
18013 this.el.removeClass('active');
18015 } else if (!this.el.hasClass('active')) {
18016 this.el.addClass('active');
18019 this.fireEvent('changed', this, state);
18022 onClick : function(e)
18024 e.preventDefault();
18026 if(!this.href.length){
18030 window.location.href = this.href;
18039 onTouchStart : function(e)
18041 this.swiping = false;
18043 this.startX = e.browserEvent.touches[0].clientX;
18044 this.startY = e.browserEvent.touches[0].clientY;
18047 onTouchMove : function(e)
18049 this.swiping = true;
18051 this.endX = e.browserEvent.touches[0].clientX;
18052 this.endY = e.browserEvent.touches[0].clientY;
18055 onTouchEnd : function(e)
18062 var tabGroup = this.parent();
18064 if(this.endX > this.startX){ // swiping right
18065 tabGroup.showPanelPrev();
18069 if(this.startX > this.endX){ // swiping left
18070 tabGroup.showPanelNext();
18089 * @class Roo.bootstrap.DateField
18090 * @extends Roo.bootstrap.Input
18091 * Bootstrap DateField class
18092 * @cfg {Number} weekStart default 0
18093 * @cfg {String} viewMode default empty, (months|years)
18094 * @cfg {String} minViewMode default empty, (months|years)
18095 * @cfg {Number} startDate default -Infinity
18096 * @cfg {Number} endDate default Infinity
18097 * @cfg {Boolean} todayHighlight default false
18098 * @cfg {Boolean} todayBtn default false
18099 * @cfg {Boolean} calendarWeeks default false
18100 * @cfg {Object} daysOfWeekDisabled default empty
18101 * @cfg {Boolean} singleMode default false (true | false)
18103 * @cfg {Boolean} keyboardNavigation default true
18104 * @cfg {String} language default en
18107 * Create a new DateField
18108 * @param {Object} config The config object
18111 Roo.bootstrap.DateField = function(config){
18112 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18116 * Fires when this field show.
18117 * @param {Roo.bootstrap.DateField} this
18118 * @param {Mixed} date The date value
18123 * Fires when this field hide.
18124 * @param {Roo.bootstrap.DateField} this
18125 * @param {Mixed} date The date value
18130 * Fires when select a date.
18131 * @param {Roo.bootstrap.DateField} this
18132 * @param {Mixed} date The date value
18136 * @event beforeselect
18137 * Fires when before select a date.
18138 * @param {Roo.bootstrap.DateField} this
18139 * @param {Mixed} date The date value
18141 beforeselect : true
18145 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18148 * @cfg {String} format
18149 * The default date format string which can be overriden for localization support. The format must be
18150 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18154 * @cfg {String} altFormats
18155 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18156 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18158 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18166 todayHighlight : false,
18172 keyboardNavigation: true,
18174 calendarWeeks: false,
18176 startDate: -Infinity,
18180 daysOfWeekDisabled: [],
18184 singleMode : false,
18186 UTCDate: function()
18188 return new Date(Date.UTC.apply(Date, arguments));
18191 UTCToday: function()
18193 var today = new Date();
18194 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18197 getDate: function() {
18198 var d = this.getUTCDate();
18199 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18202 getUTCDate: function() {
18206 setDate: function(d) {
18207 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18210 setUTCDate: function(d) {
18212 this.setValue(this.formatDate(this.date));
18215 onRender: function(ct, position)
18218 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18220 this.language = this.language || 'en';
18221 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18222 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18224 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18225 this.format = this.format || 'm/d/y';
18226 this.isInline = false;
18227 this.isInput = true;
18228 this.component = this.el.select('.add-on', true).first() || false;
18229 this.component = (this.component && this.component.length === 0) ? false : this.component;
18230 this.hasInput = this.component && this.inputEl().length;
18232 if (typeof(this.minViewMode === 'string')) {
18233 switch (this.minViewMode) {
18235 this.minViewMode = 1;
18238 this.minViewMode = 2;
18241 this.minViewMode = 0;
18246 if (typeof(this.viewMode === 'string')) {
18247 switch (this.viewMode) {
18260 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18262 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18264 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18266 this.picker().on('mousedown', this.onMousedown, this);
18267 this.picker().on('click', this.onClick, this);
18269 this.picker().addClass('datepicker-dropdown');
18271 this.startViewMode = this.viewMode;
18273 if(this.singleMode){
18274 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18275 v.setVisibilityMode(Roo.Element.DISPLAY);
18279 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18280 v.setStyle('width', '189px');
18284 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18285 if(!this.calendarWeeks){
18290 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18291 v.attr('colspan', function(i, val){
18292 return parseInt(val) + 1;
18297 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18299 this.setStartDate(this.startDate);
18300 this.setEndDate(this.endDate);
18302 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18309 if(this.isInline) {
18314 picker : function()
18316 return this.pickerEl;
18317 // return this.el.select('.datepicker', true).first();
18320 fillDow: function()
18322 var dowCnt = this.weekStart;
18331 if(this.calendarWeeks){
18339 while (dowCnt < this.weekStart + 7) {
18343 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18347 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18350 fillMonths: function()
18353 var months = this.picker().select('>.datepicker-months td', true).first();
18355 months.dom.innerHTML = '';
18361 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18364 months.createChild(month);
18371 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;
18373 if (this.date < this.startDate) {
18374 this.viewDate = new Date(this.startDate);
18375 } else if (this.date > this.endDate) {
18376 this.viewDate = new Date(this.endDate);
18378 this.viewDate = new Date(this.date);
18386 var d = new Date(this.viewDate),
18387 year = d.getUTCFullYear(),
18388 month = d.getUTCMonth(),
18389 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18390 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18391 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18392 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18393 currentDate = this.date && this.date.valueOf(),
18394 today = this.UTCToday();
18396 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18398 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18400 // this.picker.select('>tfoot th.today').
18401 // .text(dates[this.language].today)
18402 // .toggle(this.todayBtn !== false);
18404 this.updateNavArrows();
18407 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18409 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18411 prevMonth.setUTCDate(day);
18413 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18415 var nextMonth = new Date(prevMonth);
18417 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18419 nextMonth = nextMonth.valueOf();
18421 var fillMonths = false;
18423 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18425 while(prevMonth.valueOf() < nextMonth) {
18428 if (prevMonth.getUTCDay() === this.weekStart) {
18430 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18438 if(this.calendarWeeks){
18439 // ISO 8601: First week contains first thursday.
18440 // ISO also states week starts on Monday, but we can be more abstract here.
18442 // Start of current week: based on weekstart/current date
18443 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18444 // Thursday of this week
18445 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18446 // First Thursday of year, year from thursday
18447 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18448 // Calendar week: ms between thursdays, div ms per day, div 7 days
18449 calWeek = (th - yth) / 864e5 / 7 + 1;
18451 fillMonths.cn.push({
18459 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18461 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18464 if (this.todayHighlight &&
18465 prevMonth.getUTCFullYear() == today.getFullYear() &&
18466 prevMonth.getUTCMonth() == today.getMonth() &&
18467 prevMonth.getUTCDate() == today.getDate()) {
18468 clsName += ' today';
18471 if (currentDate && prevMonth.valueOf() === currentDate) {
18472 clsName += ' active';
18475 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18476 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18477 clsName += ' disabled';
18480 fillMonths.cn.push({
18482 cls: 'day ' + clsName,
18483 html: prevMonth.getDate()
18486 prevMonth.setDate(prevMonth.getDate()+1);
18489 var currentYear = this.date && this.date.getUTCFullYear();
18490 var currentMonth = this.date && this.date.getUTCMonth();
18492 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18494 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18495 v.removeClass('active');
18497 if(currentYear === year && k === currentMonth){
18498 v.addClass('active');
18501 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18502 v.addClass('disabled');
18508 year = parseInt(year/10, 10) * 10;
18510 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18512 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18515 for (var i = -1; i < 11; i++) {
18516 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18518 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18526 showMode: function(dir)
18529 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18532 Roo.each(this.picker().select('>div',true).elements, function(v){
18533 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18536 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18541 if(this.isInline) {
18545 this.picker().removeClass(['bottom', 'top']);
18547 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18549 * place to the top of element!
18553 this.picker().addClass('top');
18554 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18559 this.picker().addClass('bottom');
18561 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18564 parseDate : function(value)
18566 if(!value || value instanceof Date){
18569 var v = Date.parseDate(value, this.format);
18570 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18571 v = Date.parseDate(value, 'Y-m-d');
18573 if(!v && this.altFormats){
18574 if(!this.altFormatsArray){
18575 this.altFormatsArray = this.altFormats.split("|");
18577 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18578 v = Date.parseDate(value, this.altFormatsArray[i]);
18584 formatDate : function(date, fmt)
18586 return (!date || !(date instanceof Date)) ?
18587 date : date.dateFormat(fmt || this.format);
18590 onFocus : function()
18592 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18596 onBlur : function()
18598 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18600 var d = this.inputEl().getValue();
18609 this.picker().show();
18613 this.fireEvent('show', this, this.date);
18618 if(this.isInline) {
18621 this.picker().hide();
18622 this.viewMode = this.startViewMode;
18625 this.fireEvent('hide', this, this.date);
18629 onMousedown: function(e)
18631 e.stopPropagation();
18632 e.preventDefault();
18637 Roo.bootstrap.DateField.superclass.keyup.call(this);
18641 setValue: function(v)
18643 if(this.fireEvent('beforeselect', this, v) !== false){
18644 var d = new Date(this.parseDate(v) ).clearTime();
18646 if(isNaN(d.getTime())){
18647 this.date = this.viewDate = '';
18648 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18652 v = this.formatDate(d);
18654 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18656 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18660 this.fireEvent('select', this, this.date);
18664 getValue: function()
18666 return this.formatDate(this.date);
18669 fireKey: function(e)
18671 if (!this.picker().isVisible()){
18672 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18678 var dateChanged = false,
18680 newDate, newViewDate;
18685 e.preventDefault();
18689 if (!this.keyboardNavigation) {
18692 dir = e.keyCode == 37 ? -1 : 1;
18695 newDate = this.moveYear(this.date, dir);
18696 newViewDate = this.moveYear(this.viewDate, dir);
18697 } else if (e.shiftKey){
18698 newDate = this.moveMonth(this.date, dir);
18699 newViewDate = this.moveMonth(this.viewDate, dir);
18701 newDate = new Date(this.date);
18702 newDate.setUTCDate(this.date.getUTCDate() + dir);
18703 newViewDate = new Date(this.viewDate);
18704 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18706 if (this.dateWithinRange(newDate)){
18707 this.date = newDate;
18708 this.viewDate = newViewDate;
18709 this.setValue(this.formatDate(this.date));
18711 e.preventDefault();
18712 dateChanged = true;
18717 if (!this.keyboardNavigation) {
18720 dir = e.keyCode == 38 ? -1 : 1;
18722 newDate = this.moveYear(this.date, dir);
18723 newViewDate = this.moveYear(this.viewDate, dir);
18724 } else if (e.shiftKey){
18725 newDate = this.moveMonth(this.date, dir);
18726 newViewDate = this.moveMonth(this.viewDate, dir);
18728 newDate = new Date(this.date);
18729 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18730 newViewDate = new Date(this.viewDate);
18731 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18733 if (this.dateWithinRange(newDate)){
18734 this.date = newDate;
18735 this.viewDate = newViewDate;
18736 this.setValue(this.formatDate(this.date));
18738 e.preventDefault();
18739 dateChanged = true;
18743 this.setValue(this.formatDate(this.date));
18745 e.preventDefault();
18748 this.setValue(this.formatDate(this.date));
18762 onClick: function(e)
18764 e.stopPropagation();
18765 e.preventDefault();
18767 var target = e.getTarget();
18769 if(target.nodeName.toLowerCase() === 'i'){
18770 target = Roo.get(target).dom.parentNode;
18773 var nodeName = target.nodeName;
18774 var className = target.className;
18775 var html = target.innerHTML;
18776 //Roo.log(nodeName);
18778 switch(nodeName.toLowerCase()) {
18780 switch(className) {
18786 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18787 switch(this.viewMode){
18789 this.viewDate = this.moveMonth(this.viewDate, dir);
18793 this.viewDate = this.moveYear(this.viewDate, dir);
18799 var date = new Date();
18800 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18802 this.setValue(this.formatDate(this.date));
18809 if (className.indexOf('disabled') < 0) {
18810 this.viewDate.setUTCDate(1);
18811 if (className.indexOf('month') > -1) {
18812 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18814 var year = parseInt(html, 10) || 0;
18815 this.viewDate.setUTCFullYear(year);
18819 if(this.singleMode){
18820 this.setValue(this.formatDate(this.viewDate));
18831 //Roo.log(className);
18832 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18833 var day = parseInt(html, 10) || 1;
18834 var year = this.viewDate.getUTCFullYear(),
18835 month = this.viewDate.getUTCMonth();
18837 if (className.indexOf('old') > -1) {
18844 } else if (className.indexOf('new') > -1) {
18852 //Roo.log([year,month,day]);
18853 this.date = this.UTCDate(year, month, day,0,0,0,0);
18854 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18856 //Roo.log(this.formatDate(this.date));
18857 this.setValue(this.formatDate(this.date));
18864 setStartDate: function(startDate)
18866 this.startDate = startDate || -Infinity;
18867 if (this.startDate !== -Infinity) {
18868 this.startDate = this.parseDate(this.startDate);
18871 this.updateNavArrows();
18874 setEndDate: function(endDate)
18876 this.endDate = endDate || Infinity;
18877 if (this.endDate !== Infinity) {
18878 this.endDate = this.parseDate(this.endDate);
18881 this.updateNavArrows();
18884 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18886 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18887 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18888 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18890 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18891 return parseInt(d, 10);
18894 this.updateNavArrows();
18897 updateNavArrows: function()
18899 if(this.singleMode){
18903 var d = new Date(this.viewDate),
18904 year = d.getUTCFullYear(),
18905 month = d.getUTCMonth();
18907 Roo.each(this.picker().select('.prev', true).elements, function(v){
18909 switch (this.viewMode) {
18912 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18918 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18925 Roo.each(this.picker().select('.next', true).elements, function(v){
18927 switch (this.viewMode) {
18930 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18936 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18944 moveMonth: function(date, dir)
18949 var new_date = new Date(date.valueOf()),
18950 day = new_date.getUTCDate(),
18951 month = new_date.getUTCMonth(),
18952 mag = Math.abs(dir),
18954 dir = dir > 0 ? 1 : -1;
18957 // If going back one month, make sure month is not current month
18958 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18960 return new_date.getUTCMonth() == month;
18962 // If going forward one month, make sure month is as expected
18963 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18965 return new_date.getUTCMonth() != new_month;
18967 new_month = month + dir;
18968 new_date.setUTCMonth(new_month);
18969 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18970 if (new_month < 0 || new_month > 11) {
18971 new_month = (new_month + 12) % 12;
18974 // For magnitudes >1, move one month at a time...
18975 for (var i=0; i<mag; i++) {
18976 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18977 new_date = this.moveMonth(new_date, dir);
18979 // ...then reset the day, keeping it in the new month
18980 new_month = new_date.getUTCMonth();
18981 new_date.setUTCDate(day);
18983 return new_month != new_date.getUTCMonth();
18986 // Common date-resetting loop -- if date is beyond end of month, make it
18989 new_date.setUTCDate(--day);
18990 new_date.setUTCMonth(new_month);
18995 moveYear: function(date, dir)
18997 return this.moveMonth(date, dir*12);
19000 dateWithinRange: function(date)
19002 return date >= this.startDate && date <= this.endDate;
19008 this.picker().remove();
19011 validateValue : function(value)
19013 if(value.length < 1) {
19014 if(this.allowBlank){
19020 if(value.length < this.minLength){
19023 if(value.length > this.maxLength){
19027 var vt = Roo.form.VTypes;
19028 if(!vt[this.vtype](value, this)){
19032 if(typeof this.validator == "function"){
19033 var msg = this.validator(value);
19039 if(this.regex && !this.regex.test(value)){
19043 if(typeof(this.parseDate(value)) == 'undefined'){
19047 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19051 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19061 Roo.apply(Roo.bootstrap.DateField, {
19072 html: '<i class="fa fa-arrow-left"/>'
19082 html: '<i class="fa fa-arrow-right"/>'
19124 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19125 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19126 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19127 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19128 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19141 navFnc: 'FullYear',
19146 navFnc: 'FullYear',
19151 Roo.apply(Roo.bootstrap.DateField, {
19155 cls: 'datepicker dropdown-menu roo-dynamic',
19159 cls: 'datepicker-days',
19163 cls: 'table-condensed',
19165 Roo.bootstrap.DateField.head,
19169 Roo.bootstrap.DateField.footer
19176 cls: 'datepicker-months',
19180 cls: 'table-condensed',
19182 Roo.bootstrap.DateField.head,
19183 Roo.bootstrap.DateField.content,
19184 Roo.bootstrap.DateField.footer
19191 cls: 'datepicker-years',
19195 cls: 'table-condensed',
19197 Roo.bootstrap.DateField.head,
19198 Roo.bootstrap.DateField.content,
19199 Roo.bootstrap.DateField.footer
19218 * @class Roo.bootstrap.TimeField
19219 * @extends Roo.bootstrap.Input
19220 * Bootstrap DateField class
19224 * Create a new TimeField
19225 * @param {Object} config The config object
19228 Roo.bootstrap.TimeField = function(config){
19229 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19233 * Fires when this field show.
19234 * @param {Roo.bootstrap.DateField} thisthis
19235 * @param {Mixed} date The date value
19240 * Fires when this field hide.
19241 * @param {Roo.bootstrap.DateField} this
19242 * @param {Mixed} date The date value
19247 * Fires when select a date.
19248 * @param {Roo.bootstrap.DateField} this
19249 * @param {Mixed} date The date value
19255 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19258 * @cfg {String} format
19259 * The default time format string which can be overriden for localization support. The format must be
19260 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19264 onRender: function(ct, position)
19267 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19269 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19271 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19273 this.pop = this.picker().select('>.datepicker-time',true).first();
19274 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19276 this.picker().on('mousedown', this.onMousedown, this);
19277 this.picker().on('click', this.onClick, this);
19279 this.picker().addClass('datepicker-dropdown');
19284 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19285 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19286 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19287 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19288 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19289 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19293 fireKey: function(e){
19294 if (!this.picker().isVisible()){
19295 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19301 e.preventDefault();
19309 this.onTogglePeriod();
19312 this.onIncrementMinutes();
19315 this.onDecrementMinutes();
19324 onClick: function(e) {
19325 e.stopPropagation();
19326 e.preventDefault();
19329 picker : function()
19331 return this.el.select('.datepicker', true).first();
19334 fillTime: function()
19336 var time = this.pop.select('tbody', true).first();
19338 time.dom.innerHTML = '';
19353 cls: 'hours-up glyphicon glyphicon-chevron-up'
19373 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19394 cls: 'timepicker-hour',
19409 cls: 'timepicker-minute',
19424 cls: 'btn btn-primary period',
19446 cls: 'hours-down glyphicon glyphicon-chevron-down'
19466 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19484 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19491 var hours = this.time.getHours();
19492 var minutes = this.time.getMinutes();
19505 hours = hours - 12;
19509 hours = '0' + hours;
19513 minutes = '0' + minutes;
19516 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19517 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19518 this.pop.select('button', true).first().dom.innerHTML = period;
19524 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19526 var cls = ['bottom'];
19528 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19535 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19540 this.picker().addClass(cls.join('-'));
19544 Roo.each(cls, function(c){
19546 _this.picker().setTop(_this.inputEl().getHeight());
19550 _this.picker().setTop(0 - _this.picker().getHeight());
19555 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19559 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19566 onFocus : function()
19568 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19572 onBlur : function()
19574 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19580 this.picker().show();
19585 this.fireEvent('show', this, this.date);
19590 this.picker().hide();
19593 this.fireEvent('hide', this, this.date);
19596 setTime : function()
19599 this.setValue(this.time.format(this.format));
19601 this.fireEvent('select', this, this.date);
19606 onMousedown: function(e){
19607 e.stopPropagation();
19608 e.preventDefault();
19611 onIncrementHours: function()
19613 Roo.log('onIncrementHours');
19614 this.time = this.time.add(Date.HOUR, 1);
19619 onDecrementHours: function()
19621 Roo.log('onDecrementHours');
19622 this.time = this.time.add(Date.HOUR, -1);
19626 onIncrementMinutes: function()
19628 Roo.log('onIncrementMinutes');
19629 this.time = this.time.add(Date.MINUTE, 1);
19633 onDecrementMinutes: function()
19635 Roo.log('onDecrementMinutes');
19636 this.time = this.time.add(Date.MINUTE, -1);
19640 onTogglePeriod: function()
19642 Roo.log('onTogglePeriod');
19643 this.time = this.time.add(Date.HOUR, 12);
19650 Roo.apply(Roo.bootstrap.TimeField, {
19680 cls: 'btn btn-info ok',
19692 Roo.apply(Roo.bootstrap.TimeField, {
19696 cls: 'datepicker dropdown-menu',
19700 cls: 'datepicker-time',
19704 cls: 'table-condensed',
19706 Roo.bootstrap.TimeField.content,
19707 Roo.bootstrap.TimeField.footer
19726 * @class Roo.bootstrap.MonthField
19727 * @extends Roo.bootstrap.Input
19728 * Bootstrap MonthField class
19730 * @cfg {String} language default en
19733 * Create a new MonthField
19734 * @param {Object} config The config object
19737 Roo.bootstrap.MonthField = function(config){
19738 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19743 * Fires when this field show.
19744 * @param {Roo.bootstrap.MonthField} this
19745 * @param {Mixed} date The date value
19750 * Fires when this field hide.
19751 * @param {Roo.bootstrap.MonthField} this
19752 * @param {Mixed} date The date value
19757 * Fires when select a date.
19758 * @param {Roo.bootstrap.MonthField} this
19759 * @param {String} oldvalue The old value
19760 * @param {String} newvalue The new value
19766 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19768 onRender: function(ct, position)
19771 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19773 this.language = this.language || 'en';
19774 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19775 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19777 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19778 this.isInline = false;
19779 this.isInput = true;
19780 this.component = this.el.select('.add-on', true).first() || false;
19781 this.component = (this.component && this.component.length === 0) ? false : this.component;
19782 this.hasInput = this.component && this.inputEL().length;
19784 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19786 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19788 this.picker().on('mousedown', this.onMousedown, this);
19789 this.picker().on('click', this.onClick, this);
19791 this.picker().addClass('datepicker-dropdown');
19793 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19794 v.setStyle('width', '189px');
19801 if(this.isInline) {
19807 setValue: function(v, suppressEvent)
19809 var o = this.getValue();
19811 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19815 if(suppressEvent !== true){
19816 this.fireEvent('select', this, o, v);
19821 getValue: function()
19826 onClick: function(e)
19828 e.stopPropagation();
19829 e.preventDefault();
19831 var target = e.getTarget();
19833 if(target.nodeName.toLowerCase() === 'i'){
19834 target = Roo.get(target).dom.parentNode;
19837 var nodeName = target.nodeName;
19838 var className = target.className;
19839 var html = target.innerHTML;
19841 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19845 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19847 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19853 picker : function()
19855 return this.pickerEl;
19858 fillMonths: function()
19861 var months = this.picker().select('>.datepicker-months td', true).first();
19863 months.dom.innerHTML = '';
19869 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19872 months.createChild(month);
19881 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19882 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19885 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19886 e.removeClass('active');
19888 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19889 e.addClass('active');
19896 if(this.isInline) {
19900 this.picker().removeClass(['bottom', 'top']);
19902 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19904 * place to the top of element!
19908 this.picker().addClass('top');
19909 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19914 this.picker().addClass('bottom');
19916 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19919 onFocus : function()
19921 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19925 onBlur : function()
19927 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19929 var d = this.inputEl().getValue();
19938 this.picker().show();
19939 this.picker().select('>.datepicker-months', true).first().show();
19943 this.fireEvent('show', this, this.date);
19948 if(this.isInline) {
19951 this.picker().hide();
19952 this.fireEvent('hide', this, this.date);
19956 onMousedown: function(e)
19958 e.stopPropagation();
19959 e.preventDefault();
19964 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19968 fireKey: function(e)
19970 if (!this.picker().isVisible()){
19971 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19982 e.preventDefault();
19986 dir = e.keyCode == 37 ? -1 : 1;
19988 this.vIndex = this.vIndex + dir;
19990 if(this.vIndex < 0){
19994 if(this.vIndex > 11){
19998 if(isNaN(this.vIndex)){
20002 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20008 dir = e.keyCode == 38 ? -1 : 1;
20010 this.vIndex = this.vIndex + dir * 4;
20012 if(this.vIndex < 0){
20016 if(this.vIndex > 11){
20020 if(isNaN(this.vIndex)){
20024 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20029 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20030 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20034 e.preventDefault();
20037 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20038 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20054 this.picker().remove();
20059 Roo.apply(Roo.bootstrap.MonthField, {
20078 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20079 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20084 Roo.apply(Roo.bootstrap.MonthField, {
20088 cls: 'datepicker dropdown-menu roo-dynamic',
20092 cls: 'datepicker-months',
20096 cls: 'table-condensed',
20098 Roo.bootstrap.DateField.content
20118 * @class Roo.bootstrap.CheckBox
20119 * @extends Roo.bootstrap.Input
20120 * Bootstrap CheckBox class
20122 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20123 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20124 * @cfg {String} boxLabel The text that appears beside the checkbox
20125 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20126 * @cfg {Boolean} checked initnal the element
20127 * @cfg {Boolean} inline inline the element (default false)
20128 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20129 * @cfg {String} tooltip label tooltip
20132 * Create a new CheckBox
20133 * @param {Object} config The config object
20136 Roo.bootstrap.CheckBox = function(config){
20137 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20142 * Fires when the element is checked or unchecked.
20143 * @param {Roo.bootstrap.CheckBox} this This input
20144 * @param {Boolean} checked The new checked value
20149 * Fires when the element is click.
20150 * @param {Roo.bootstrap.CheckBox} this This input
20157 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20159 inputType: 'checkbox',
20168 getAutoCreate : function()
20170 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20176 cfg.cls = 'form-group ' + this.inputType; //input-group
20179 cfg.cls += ' ' + this.inputType + '-inline';
20185 type : this.inputType,
20186 value : this.inputValue,
20187 cls : 'roo-' + this.inputType, //'form-box',
20188 placeholder : this.placeholder || ''
20192 if(this.inputType != 'radio'){
20196 cls : 'roo-hidden-value',
20197 value : this.checked ? this.inputValue : this.valueOff
20202 if (this.weight) { // Validity check?
20203 cfg.cls += " " + this.inputType + "-" + this.weight;
20206 if (this.disabled) {
20207 input.disabled=true;
20211 input.checked = this.checked;
20216 input.name = this.name;
20218 if(this.inputType != 'radio'){
20219 hidden.name = this.name;
20220 input.name = '_hidden_' + this.name;
20225 input.cls += ' input-' + this.size;
20230 ['xs','sm','md','lg'].map(function(size){
20231 if (settings[size]) {
20232 cfg.cls += ' col-' + size + '-' + settings[size];
20236 var inputblock = input;
20238 if (this.before || this.after) {
20241 cls : 'input-group',
20246 inputblock.cn.push({
20248 cls : 'input-group-addon',
20253 inputblock.cn.push(input);
20255 if(this.inputType != 'radio'){
20256 inputblock.cn.push(hidden);
20260 inputblock.cn.push({
20262 cls : 'input-group-addon',
20269 if (align ==='left' && this.fieldLabel.length) {
20270 // Roo.log("left and has label");
20275 cls : 'control-label',
20276 html : this.fieldLabel
20286 if(this.labelWidth > 12){
20287 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20290 if(this.labelWidth < 13 && this.labelmd == 0){
20291 this.labelmd = this.labelWidth;
20294 if(this.labellg > 0){
20295 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20296 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20299 if(this.labelmd > 0){
20300 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20301 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20304 if(this.labelsm > 0){
20305 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20306 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20309 if(this.labelxs > 0){
20310 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20311 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20314 } else if ( this.fieldLabel.length) {
20315 // Roo.log(" label");
20319 tag: this.boxLabel ? 'span' : 'label',
20321 cls: 'control-label box-input-label',
20322 //cls : 'input-group-addon',
20323 html : this.fieldLabel
20332 // Roo.log(" no label && no align");
20333 cfg.cn = [ inputblock ] ;
20339 var boxLabelCfg = {
20341 //'for': id, // box label is handled by onclick - so no for...
20343 html: this.boxLabel
20347 boxLabelCfg.tooltip = this.tooltip;
20350 cfg.cn.push(boxLabelCfg);
20353 if(this.inputType != 'radio'){
20354 cfg.cn.push(hidden);
20362 * return the real input element.
20364 inputEl: function ()
20366 return this.el.select('input.roo-' + this.inputType,true).first();
20368 hiddenEl: function ()
20370 return this.el.select('input.roo-hidden-value',true).first();
20373 labelEl: function()
20375 return this.el.select('label.control-label',true).first();
20377 /* depricated... */
20381 return this.labelEl();
20384 boxLabelEl: function()
20386 return this.el.select('label.box-label',true).first();
20389 initEvents : function()
20391 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20393 this.inputEl().on('click', this.onClick, this);
20395 if (this.boxLabel) {
20396 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20399 this.startValue = this.getValue();
20402 Roo.bootstrap.CheckBox.register(this);
20406 onClick : function()
20408 this.setChecked(!this.checked);
20411 setChecked : function(state,suppressEvent)
20413 this.startValue = this.getValue();
20415 if(this.inputType == 'radio'){
20417 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20418 e.dom.checked = false;
20421 this.inputEl().dom.checked = true;
20423 this.inputEl().dom.value = this.inputValue;
20425 if(suppressEvent !== true){
20426 this.fireEvent('check', this, true);
20434 this.checked = state;
20436 this.inputEl().dom.checked = state;
20439 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20441 if(suppressEvent !== true){
20442 this.fireEvent('check', this, state);
20448 getValue : function()
20450 if(this.inputType == 'radio'){
20451 return this.getGroupValue();
20454 return this.hiddenEl().dom.value;
20458 getGroupValue : function()
20460 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20464 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20467 setValue : function(v,suppressEvent)
20469 if(this.inputType == 'radio'){
20470 this.setGroupValue(v, suppressEvent);
20474 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20479 setGroupValue : function(v, suppressEvent)
20481 this.startValue = this.getValue();
20483 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20484 e.dom.checked = false;
20486 if(e.dom.value == v){
20487 e.dom.checked = true;
20491 if(suppressEvent !== true){
20492 this.fireEvent('check', this, true);
20500 validate : function()
20504 (this.inputType == 'radio' && this.validateRadio()) ||
20505 (this.inputType == 'checkbox' && this.validateCheckbox())
20511 this.markInvalid();
20515 validateRadio : function()
20517 if(this.allowBlank){
20523 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20524 if(!e.dom.checked){
20536 validateCheckbox : function()
20539 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20540 //return (this.getValue() == this.inputValue) ? true : false;
20543 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20551 for(var i in group){
20556 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20563 * Mark this field as valid
20565 markValid : function()
20569 this.fireEvent('valid', this);
20571 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20574 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20581 if(this.inputType == 'radio'){
20582 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20583 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20584 e.findParent('.form-group', false, true).addClass(_this.validClass);
20591 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20592 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20596 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20602 for(var i in group){
20603 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20604 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20609 * Mark this field as invalid
20610 * @param {String} msg The validation message
20612 markInvalid : function(msg)
20614 if(this.allowBlank){
20620 this.fireEvent('invalid', this, msg);
20622 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20625 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20629 label.markInvalid();
20632 if(this.inputType == 'radio'){
20633 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20634 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20635 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20642 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20643 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20647 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20653 for(var i in group){
20654 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20655 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20660 clearInvalid : function()
20662 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20664 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20666 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20669 label.iconEl.removeClass(label.validClass);
20670 label.iconEl.removeClass(label.invalidClass);
20674 disable : function()
20676 if(this.inputType != 'radio'){
20677 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20684 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20685 _this.getActionEl().addClass(this.disabledClass);
20686 e.dom.disabled = true;
20690 this.disabled = true;
20691 this.fireEvent("disable", this);
20695 enable : function()
20697 if(this.inputType != 'radio'){
20698 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20705 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20706 _this.getActionEl().removeClass(this.disabledClass);
20707 e.dom.disabled = false;
20711 this.disabled = false;
20712 this.fireEvent("enable", this);
20718 Roo.apply(Roo.bootstrap.CheckBox, {
20723 * register a CheckBox Group
20724 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20726 register : function(checkbox)
20728 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20729 this.groups[checkbox.groupId] = {};
20732 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20736 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20740 * fetch a CheckBox Group based on the group ID
20741 * @param {string} the group ID
20742 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20744 get: function(groupId) {
20745 if (typeof(this.groups[groupId]) == 'undefined') {
20749 return this.groups[groupId] ;
20762 * @class Roo.bootstrap.Radio
20763 * @extends Roo.bootstrap.Component
20764 * Bootstrap Radio class
20765 * @cfg {String} boxLabel - the label associated
20766 * @cfg {String} value - the value of radio
20769 * Create a new Radio
20770 * @param {Object} config The config object
20772 Roo.bootstrap.Radio = function(config){
20773 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20777 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20783 getAutoCreate : function()
20787 cls : 'form-group radio',
20792 html : this.boxLabel
20800 initEvents : function()
20802 this.parent().register(this);
20804 this.el.on('click', this.onClick, this);
20808 onClick : function()
20810 this.setChecked(true);
20813 setChecked : function(state, suppressEvent)
20815 this.parent().setValue(this.value, suppressEvent);
20819 setBoxLabel : function(v)
20824 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20839 * @class Roo.bootstrap.SecurePass
20840 * @extends Roo.bootstrap.Input
20841 * Bootstrap SecurePass class
20845 * Create a new SecurePass
20846 * @param {Object} config The config object
20849 Roo.bootstrap.SecurePass = function (config) {
20850 // these go here, so the translation tool can replace them..
20852 PwdEmpty: "Please type a password, and then retype it to confirm.",
20853 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20854 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20855 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20856 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20857 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20858 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20859 TooWeak: "Your password is Too Weak."
20861 this.meterLabel = "Password strength:";
20862 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20863 this.meterClass = [
20864 "roo-password-meter-tooweak",
20865 "roo-password-meter-weak",
20866 "roo-password-meter-medium",
20867 "roo-password-meter-strong",
20868 "roo-password-meter-grey"
20873 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20876 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20878 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20880 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20881 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20882 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20883 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20884 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20885 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20886 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20896 * @cfg {String/Object} Label for the strength meter (defaults to
20897 * 'Password strength:')
20902 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20903 * ['Weak', 'Medium', 'Strong'])
20906 pwdStrengths: false,
20919 initEvents: function ()
20921 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20923 if (this.el.is('input[type=password]') && Roo.isSafari) {
20924 this.el.on('keydown', this.SafariOnKeyDown, this);
20927 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20930 onRender: function (ct, position)
20932 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20933 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20934 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20936 this.trigger.createChild({
20941 cls: 'roo-password-meter-grey col-xs-12',
20944 //width: this.meterWidth + 'px'
20948 cls: 'roo-password-meter-text'
20954 if (this.hideTrigger) {
20955 this.trigger.setDisplayed(false);
20957 this.setSize(this.width || '', this.height || '');
20960 onDestroy: function ()
20962 if (this.trigger) {
20963 this.trigger.removeAllListeners();
20964 this.trigger.remove();
20967 this.wrap.remove();
20969 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20972 checkStrength: function ()
20974 var pwd = this.inputEl().getValue();
20975 if (pwd == this._lastPwd) {
20980 if (this.ClientSideStrongPassword(pwd)) {
20982 } else if (this.ClientSideMediumPassword(pwd)) {
20984 } else if (this.ClientSideWeakPassword(pwd)) {
20990 Roo.log('strength1: ' + strength);
20992 //var pm = this.trigger.child('div/div/div').dom;
20993 var pm = this.trigger.child('div/div');
20994 pm.removeClass(this.meterClass);
20995 pm.addClass(this.meterClass[strength]);
20998 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21000 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21002 this._lastPwd = pwd;
21006 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21008 this._lastPwd = '';
21010 var pm = this.trigger.child('div/div');
21011 pm.removeClass(this.meterClass);
21012 pm.addClass('roo-password-meter-grey');
21015 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21018 this.inputEl().dom.type='password';
21021 validateValue: function (value)
21024 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21027 if (value.length == 0) {
21028 if (this.allowBlank) {
21029 this.clearInvalid();
21033 this.markInvalid(this.errors.PwdEmpty);
21034 this.errorMsg = this.errors.PwdEmpty;
21042 if ('[\x21-\x7e]*'.match(value)) {
21043 this.markInvalid(this.errors.PwdBadChar);
21044 this.errorMsg = this.errors.PwdBadChar;
21047 if (value.length < 6) {
21048 this.markInvalid(this.errors.PwdShort);
21049 this.errorMsg = this.errors.PwdShort;
21052 if (value.length > 16) {
21053 this.markInvalid(this.errors.PwdLong);
21054 this.errorMsg = this.errors.PwdLong;
21058 if (this.ClientSideStrongPassword(value)) {
21060 } else if (this.ClientSideMediumPassword(value)) {
21062 } else if (this.ClientSideWeakPassword(value)) {
21069 if (strength < 2) {
21070 //this.markInvalid(this.errors.TooWeak);
21071 this.errorMsg = this.errors.TooWeak;
21076 console.log('strength2: ' + strength);
21078 //var pm = this.trigger.child('div/div/div').dom;
21080 var pm = this.trigger.child('div/div');
21081 pm.removeClass(this.meterClass);
21082 pm.addClass(this.meterClass[strength]);
21084 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21086 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21088 this.errorMsg = '';
21092 CharacterSetChecks: function (type)
21095 this.fResult = false;
21098 isctype: function (character, type)
21101 case this.kCapitalLetter:
21102 if (character >= 'A' && character <= 'Z') {
21107 case this.kSmallLetter:
21108 if (character >= 'a' && character <= 'z') {
21114 if (character >= '0' && character <= '9') {
21119 case this.kPunctuation:
21120 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21131 IsLongEnough: function (pwd, size)
21133 return !(pwd == null || isNaN(size) || pwd.length < size);
21136 SpansEnoughCharacterSets: function (word, nb)
21138 if (!this.IsLongEnough(word, nb))
21143 var characterSetChecks = new Array(
21144 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21145 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21148 for (var index = 0; index < word.length; ++index) {
21149 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21150 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21151 characterSetChecks[nCharSet].fResult = true;
21158 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21159 if (characterSetChecks[nCharSet].fResult) {
21164 if (nCharSets < nb) {
21170 ClientSideStrongPassword: function (pwd)
21172 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21175 ClientSideMediumPassword: function (pwd)
21177 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21180 ClientSideWeakPassword: function (pwd)
21182 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21185 })//<script type="text/javascript">
21188 * Based Ext JS Library 1.1.1
21189 * Copyright(c) 2006-2007, Ext JS, LLC.
21195 * @class Roo.HtmlEditorCore
21196 * @extends Roo.Component
21197 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21199 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21202 Roo.HtmlEditorCore = function(config){
21205 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21210 * @event initialize
21211 * Fires when the editor is fully initialized (including the iframe)
21212 * @param {Roo.HtmlEditorCore} this
21217 * Fires when the editor is first receives the focus. Any insertion must wait
21218 * until after this event.
21219 * @param {Roo.HtmlEditorCore} this
21223 * @event beforesync
21224 * Fires before the textarea is updated with content from the editor iframe. Return false
21225 * to cancel the sync.
21226 * @param {Roo.HtmlEditorCore} this
21227 * @param {String} html
21231 * @event beforepush
21232 * Fires before the iframe editor is updated with content from the textarea. Return false
21233 * to cancel the push.
21234 * @param {Roo.HtmlEditorCore} this
21235 * @param {String} html
21240 * Fires when the textarea is updated with content from the editor iframe.
21241 * @param {Roo.HtmlEditorCore} this
21242 * @param {String} html
21247 * Fires when the iframe editor is updated with content from the textarea.
21248 * @param {Roo.HtmlEditorCore} this
21249 * @param {String} html
21254 * @event editorevent
21255 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21256 * @param {Roo.HtmlEditorCore} this
21262 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21264 // defaults : white / black...
21265 this.applyBlacklists();
21272 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21276 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21282 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21287 * @cfg {Number} height (in pixels)
21291 * @cfg {Number} width (in pixels)
21296 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21299 stylesheets: false,
21304 // private properties
21305 validationEvent : false,
21307 initialized : false,
21309 sourceEditMode : false,
21310 onFocus : Roo.emptyFn,
21312 hideMode:'offsets',
21316 // blacklist + whitelisted elements..
21323 * Protected method that will not generally be called directly. It
21324 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21325 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21327 getDocMarkup : function(){
21331 // inherit styels from page...??
21332 if (this.stylesheets === false) {
21334 Roo.get(document.head).select('style').each(function(node) {
21335 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21338 Roo.get(document.head).select('link').each(function(node) {
21339 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21342 } else if (!this.stylesheets.length) {
21344 st = '<style type="text/css">' +
21345 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21348 st = '<style type="text/css">' +
21353 st += '<style type="text/css">' +
21354 'IMG { cursor: pointer } ' +
21357 var cls = 'roo-htmleditor-body';
21359 if(this.bodyCls.length){
21360 cls += ' ' + this.bodyCls;
21363 return '<html><head>' + st +
21364 //<style type="text/css">' +
21365 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21367 ' </head><body class="' + cls + '"></body></html>';
21371 onRender : function(ct, position)
21374 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21375 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21378 this.el.dom.style.border = '0 none';
21379 this.el.dom.setAttribute('tabIndex', -1);
21380 this.el.addClass('x-hidden hide');
21384 if(Roo.isIE){ // fix IE 1px bogus margin
21385 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21389 this.frameId = Roo.id();
21393 var iframe = this.owner.wrap.createChild({
21395 cls: 'form-control', // bootstrap..
21397 name: this.frameId,
21398 frameBorder : 'no',
21399 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21404 this.iframe = iframe.dom;
21406 this.assignDocWin();
21408 this.doc.designMode = 'on';
21411 this.doc.write(this.getDocMarkup());
21415 var task = { // must defer to wait for browser to be ready
21417 //console.log("run task?" + this.doc.readyState);
21418 this.assignDocWin();
21419 if(this.doc.body || this.doc.readyState == 'complete'){
21421 this.doc.designMode="on";
21425 Roo.TaskMgr.stop(task);
21426 this.initEditor.defer(10, this);
21433 Roo.TaskMgr.start(task);
21438 onResize : function(w, h)
21440 Roo.log('resize: ' +w + ',' + h );
21441 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21445 if(typeof w == 'number'){
21447 this.iframe.style.width = w + 'px';
21449 if(typeof h == 'number'){
21451 this.iframe.style.height = h + 'px';
21453 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21460 * Toggles the editor between standard and source edit mode.
21461 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21463 toggleSourceEdit : function(sourceEditMode){
21465 this.sourceEditMode = sourceEditMode === true;
21467 if(this.sourceEditMode){
21469 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21472 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21473 //this.iframe.className = '';
21476 //this.setSize(this.owner.wrap.getSize());
21477 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21484 * Protected method that will not generally be called directly. If you need/want
21485 * custom HTML cleanup, this is the method you should override.
21486 * @param {String} html The HTML to be cleaned
21487 * return {String} The cleaned HTML
21489 cleanHtml : function(html){
21490 html = String(html);
21491 if(html.length > 5){
21492 if(Roo.isSafari){ // strip safari nonsense
21493 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21496 if(html == ' '){
21503 * HTML Editor -> Textarea
21504 * Protected method that will not generally be called directly. Syncs the contents
21505 * of the editor iframe with the textarea.
21507 syncValue : function(){
21508 if(this.initialized){
21509 var bd = (this.doc.body || this.doc.documentElement);
21510 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21511 var html = bd.innerHTML;
21513 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21514 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21516 html = '<div style="'+m[0]+'">' + html + '</div>';
21519 html = this.cleanHtml(html);
21520 // fix up the special chars.. normaly like back quotes in word...
21521 // however we do not want to do this with chinese..
21522 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21523 var cc = b.charCodeAt();
21525 (cc >= 0x4E00 && cc < 0xA000 ) ||
21526 (cc >= 0x3400 && cc < 0x4E00 ) ||
21527 (cc >= 0xf900 && cc < 0xfb00 )
21533 if(this.owner.fireEvent('beforesync', this, html) !== false){
21534 this.el.dom.value = html;
21535 this.owner.fireEvent('sync', this, html);
21541 * Protected method that will not generally be called directly. Pushes the value of the textarea
21542 * into the iframe editor.
21544 pushValue : function(){
21545 if(this.initialized){
21546 var v = this.el.dom.value.trim();
21548 // if(v.length < 1){
21552 if(this.owner.fireEvent('beforepush', this, v) !== false){
21553 var d = (this.doc.body || this.doc.documentElement);
21555 this.cleanUpPaste();
21556 this.el.dom.value = d.innerHTML;
21557 this.owner.fireEvent('push', this, v);
21563 deferFocus : function(){
21564 this.focus.defer(10, this);
21568 focus : function(){
21569 if(this.win && !this.sourceEditMode){
21576 assignDocWin: function()
21578 var iframe = this.iframe;
21581 this.doc = iframe.contentWindow.document;
21582 this.win = iframe.contentWindow;
21584 // if (!Roo.get(this.frameId)) {
21587 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21588 // this.win = Roo.get(this.frameId).dom.contentWindow;
21590 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21594 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21595 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21600 initEditor : function(){
21601 //console.log("INIT EDITOR");
21602 this.assignDocWin();
21606 this.doc.designMode="on";
21608 this.doc.write(this.getDocMarkup());
21611 var dbody = (this.doc.body || this.doc.documentElement);
21612 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21613 // this copies styles from the containing element into thsi one..
21614 // not sure why we need all of this..
21615 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21617 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21618 //ss['background-attachment'] = 'fixed'; // w3c
21619 dbody.bgProperties = 'fixed'; // ie
21620 //Roo.DomHelper.applyStyles(dbody, ss);
21621 Roo.EventManager.on(this.doc, {
21622 //'mousedown': this.onEditorEvent,
21623 'mouseup': this.onEditorEvent,
21624 'dblclick': this.onEditorEvent,
21625 'click': this.onEditorEvent,
21626 'keyup': this.onEditorEvent,
21631 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21633 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21634 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21636 this.initialized = true;
21638 this.owner.fireEvent('initialize', this);
21643 onDestroy : function(){
21649 //for (var i =0; i < this.toolbars.length;i++) {
21650 // // fixme - ask toolbars for heights?
21651 // this.toolbars[i].onDestroy();
21654 //this.wrap.dom.innerHTML = '';
21655 //this.wrap.remove();
21660 onFirstFocus : function(){
21662 this.assignDocWin();
21665 this.activated = true;
21668 if(Roo.isGecko){ // prevent silly gecko errors
21670 var s = this.win.getSelection();
21671 if(!s.focusNode || s.focusNode.nodeType != 3){
21672 var r = s.getRangeAt(0);
21673 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21678 this.execCmd('useCSS', true);
21679 this.execCmd('styleWithCSS', false);
21682 this.owner.fireEvent('activate', this);
21686 adjustFont: function(btn){
21687 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21688 //if(Roo.isSafari){ // safari
21691 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21692 if(Roo.isSafari){ // safari
21693 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21694 v = (v < 10) ? 10 : v;
21695 v = (v > 48) ? 48 : v;
21696 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21701 v = Math.max(1, v+adjust);
21703 this.execCmd('FontSize', v );
21706 onEditorEvent : function(e)
21708 this.owner.fireEvent('editorevent', this, e);
21709 // this.updateToolbar();
21710 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21713 insertTag : function(tg)
21715 // could be a bit smarter... -> wrap the current selected tRoo..
21716 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21718 range = this.createRange(this.getSelection());
21719 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21720 wrappingNode.appendChild(range.extractContents());
21721 range.insertNode(wrappingNode);
21728 this.execCmd("formatblock", tg);
21732 insertText : function(txt)
21736 var range = this.createRange();
21737 range.deleteContents();
21738 //alert(Sender.getAttribute('label'));
21740 range.insertNode(this.doc.createTextNode(txt));
21746 * Executes a Midas editor command on the editor document and performs necessary focus and
21747 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21748 * @param {String} cmd The Midas command
21749 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21751 relayCmd : function(cmd, value){
21753 this.execCmd(cmd, value);
21754 this.owner.fireEvent('editorevent', this);
21755 //this.updateToolbar();
21756 this.owner.deferFocus();
21760 * Executes a Midas editor command directly on the editor document.
21761 * For visual commands, you should use {@link #relayCmd} instead.
21762 * <b>This should only be called after the editor is initialized.</b>
21763 * @param {String} cmd The Midas command
21764 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21766 execCmd : function(cmd, value){
21767 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21774 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21776 * @param {String} text | dom node..
21778 insertAtCursor : function(text)
21781 if(!this.activated){
21787 var r = this.doc.selection.createRange();
21798 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21802 // from jquery ui (MIT licenced)
21804 var win = this.win;
21806 if (win.getSelection && win.getSelection().getRangeAt) {
21807 range = win.getSelection().getRangeAt(0);
21808 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21809 range.insertNode(node);
21810 } else if (win.document.selection && win.document.selection.createRange) {
21811 // no firefox support
21812 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21813 win.document.selection.createRange().pasteHTML(txt);
21815 // no firefox support
21816 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21817 this.execCmd('InsertHTML', txt);
21826 mozKeyPress : function(e){
21828 var c = e.getCharCode(), cmd;
21831 c = String.fromCharCode(c).toLowerCase();
21845 this.cleanUpPaste.defer(100, this);
21853 e.preventDefault();
21861 fixKeys : function(){ // load time branching for fastest keydown performance
21863 return function(e){
21864 var k = e.getKey(), r;
21867 r = this.doc.selection.createRange();
21870 r.pasteHTML('    ');
21877 r = this.doc.selection.createRange();
21879 var target = r.parentElement();
21880 if(!target || target.tagName.toLowerCase() != 'li'){
21882 r.pasteHTML('<br />');
21888 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21889 this.cleanUpPaste.defer(100, this);
21895 }else if(Roo.isOpera){
21896 return function(e){
21897 var k = e.getKey();
21901 this.execCmd('InsertHTML','    ');
21904 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21905 this.cleanUpPaste.defer(100, this);
21910 }else if(Roo.isSafari){
21911 return function(e){
21912 var k = e.getKey();
21916 this.execCmd('InsertText','\t');
21920 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21921 this.cleanUpPaste.defer(100, this);
21929 getAllAncestors: function()
21931 var p = this.getSelectedNode();
21934 a.push(p); // push blank onto stack..
21935 p = this.getParentElement();
21939 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21943 a.push(this.doc.body);
21947 lastSelNode : false,
21950 getSelection : function()
21952 this.assignDocWin();
21953 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21956 getSelectedNode: function()
21958 // this may only work on Gecko!!!
21960 // should we cache this!!!!
21965 var range = this.createRange(this.getSelection()).cloneRange();
21968 var parent = range.parentElement();
21970 var testRange = range.duplicate();
21971 testRange.moveToElementText(parent);
21972 if (testRange.inRange(range)) {
21975 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21978 parent = parent.parentElement;
21983 // is ancestor a text element.
21984 var ac = range.commonAncestorContainer;
21985 if (ac.nodeType == 3) {
21986 ac = ac.parentNode;
21989 var ar = ac.childNodes;
21992 var other_nodes = [];
21993 var has_other_nodes = false;
21994 for (var i=0;i<ar.length;i++) {
21995 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21998 // fullly contained node.
22000 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22005 // probably selected..
22006 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22007 other_nodes.push(ar[i]);
22011 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22016 has_other_nodes = true;
22018 if (!nodes.length && other_nodes.length) {
22019 nodes= other_nodes;
22021 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22027 createRange: function(sel)
22029 // this has strange effects when using with
22030 // top toolbar - not sure if it's a great idea.
22031 //this.editor.contentWindow.focus();
22032 if (typeof sel != "undefined") {
22034 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22036 return this.doc.createRange();
22039 return this.doc.createRange();
22042 getParentElement: function()
22045 this.assignDocWin();
22046 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22048 var range = this.createRange(sel);
22051 var p = range.commonAncestorContainer;
22052 while (p.nodeType == 3) { // text node
22063 * Range intersection.. the hard stuff...
22067 * [ -- selected range --- ]
22071 * if end is before start or hits it. fail.
22072 * if start is after end or hits it fail.
22074 * if either hits (but other is outside. - then it's not
22080 // @see http://www.thismuchiknow.co.uk/?p=64.
22081 rangeIntersectsNode : function(range, node)
22083 var nodeRange = node.ownerDocument.createRange();
22085 nodeRange.selectNode(node);
22087 nodeRange.selectNodeContents(node);
22090 var rangeStartRange = range.cloneRange();
22091 rangeStartRange.collapse(true);
22093 var rangeEndRange = range.cloneRange();
22094 rangeEndRange.collapse(false);
22096 var nodeStartRange = nodeRange.cloneRange();
22097 nodeStartRange.collapse(true);
22099 var nodeEndRange = nodeRange.cloneRange();
22100 nodeEndRange.collapse(false);
22102 return rangeStartRange.compareBoundaryPoints(
22103 Range.START_TO_START, nodeEndRange) == -1 &&
22104 rangeEndRange.compareBoundaryPoints(
22105 Range.START_TO_START, nodeStartRange) == 1;
22109 rangeCompareNode : function(range, node)
22111 var nodeRange = node.ownerDocument.createRange();
22113 nodeRange.selectNode(node);
22115 nodeRange.selectNodeContents(node);
22119 range.collapse(true);
22121 nodeRange.collapse(true);
22123 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22124 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22126 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22128 var nodeIsBefore = ss == 1;
22129 var nodeIsAfter = ee == -1;
22131 if (nodeIsBefore && nodeIsAfter) {
22134 if (!nodeIsBefore && nodeIsAfter) {
22135 return 1; //right trailed.
22138 if (nodeIsBefore && !nodeIsAfter) {
22139 return 2; // left trailed.
22145 // private? - in a new class?
22146 cleanUpPaste : function()
22148 // cleans up the whole document..
22149 Roo.log('cleanuppaste');
22151 this.cleanUpChildren(this.doc.body);
22152 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22153 if (clean != this.doc.body.innerHTML) {
22154 this.doc.body.innerHTML = clean;
22159 cleanWordChars : function(input) {// change the chars to hex code
22160 var he = Roo.HtmlEditorCore;
22162 var output = input;
22163 Roo.each(he.swapCodes, function(sw) {
22164 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22166 output = output.replace(swapper, sw[1]);
22173 cleanUpChildren : function (n)
22175 if (!n.childNodes.length) {
22178 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22179 this.cleanUpChild(n.childNodes[i]);
22186 cleanUpChild : function (node)
22189 //console.log(node);
22190 if (node.nodeName == "#text") {
22191 // clean up silly Windows -- stuff?
22194 if (node.nodeName == "#comment") {
22195 node.parentNode.removeChild(node);
22196 // clean up silly Windows -- stuff?
22199 var lcname = node.tagName.toLowerCase();
22200 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22201 // whitelist of tags..
22203 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22205 node.parentNode.removeChild(node);
22210 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22212 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22213 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22215 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22216 // remove_keep_children = true;
22219 if (remove_keep_children) {
22220 this.cleanUpChildren(node);
22221 // inserts everything just before this node...
22222 while (node.childNodes.length) {
22223 var cn = node.childNodes[0];
22224 node.removeChild(cn);
22225 node.parentNode.insertBefore(cn, node);
22227 node.parentNode.removeChild(node);
22231 if (!node.attributes || !node.attributes.length) {
22232 this.cleanUpChildren(node);
22236 function cleanAttr(n,v)
22239 if (v.match(/^\./) || v.match(/^\//)) {
22242 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22245 if (v.match(/^#/)) {
22248 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22249 node.removeAttribute(n);
22253 var cwhite = this.cwhite;
22254 var cblack = this.cblack;
22256 function cleanStyle(n,v)
22258 if (v.match(/expression/)) { //XSS?? should we even bother..
22259 node.removeAttribute(n);
22263 var parts = v.split(/;/);
22266 Roo.each(parts, function(p) {
22267 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22271 var l = p.split(':').shift().replace(/\s+/g,'');
22272 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22274 if ( cwhite.length && cblack.indexOf(l) > -1) {
22275 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22276 //node.removeAttribute(n);
22280 // only allow 'c whitelisted system attributes'
22281 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22282 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22283 //node.removeAttribute(n);
22293 if (clean.length) {
22294 node.setAttribute(n, clean.join(';'));
22296 node.removeAttribute(n);
22302 for (var i = node.attributes.length-1; i > -1 ; i--) {
22303 var a = node.attributes[i];
22306 if (a.name.toLowerCase().substr(0,2)=='on') {
22307 node.removeAttribute(a.name);
22310 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22311 node.removeAttribute(a.name);
22314 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22315 cleanAttr(a.name,a.value); // fixme..
22318 if (a.name == 'style') {
22319 cleanStyle(a.name,a.value);
22322 /// clean up MS crap..
22323 // tecnically this should be a list of valid class'es..
22326 if (a.name == 'class') {
22327 if (a.value.match(/^Mso/)) {
22328 node.className = '';
22331 if (a.value.match(/^body$/)) {
22332 node.className = '';
22343 this.cleanUpChildren(node);
22349 * Clean up MS wordisms...
22351 cleanWord : function(node)
22356 this.cleanWord(this.doc.body);
22359 if (node.nodeName == "#text") {
22360 // clean up silly Windows -- stuff?
22363 if (node.nodeName == "#comment") {
22364 node.parentNode.removeChild(node);
22365 // clean up silly Windows -- stuff?
22369 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22370 node.parentNode.removeChild(node);
22374 // remove - but keep children..
22375 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22376 while (node.childNodes.length) {
22377 var cn = node.childNodes[0];
22378 node.removeChild(cn);
22379 node.parentNode.insertBefore(cn, node);
22381 node.parentNode.removeChild(node);
22382 this.iterateChildren(node, this.cleanWord);
22386 if (node.className.length) {
22388 var cn = node.className.split(/\W+/);
22390 Roo.each(cn, function(cls) {
22391 if (cls.match(/Mso[a-zA-Z]+/)) {
22396 node.className = cna.length ? cna.join(' ') : '';
22398 node.removeAttribute("class");
22402 if (node.hasAttribute("lang")) {
22403 node.removeAttribute("lang");
22406 if (node.hasAttribute("style")) {
22408 var styles = node.getAttribute("style").split(";");
22410 Roo.each(styles, function(s) {
22411 if (!s.match(/:/)) {
22414 var kv = s.split(":");
22415 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22418 // what ever is left... we allow.
22421 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22422 if (!nstyle.length) {
22423 node.removeAttribute('style');
22426 this.iterateChildren(node, this.cleanWord);
22432 * iterateChildren of a Node, calling fn each time, using this as the scole..
22433 * @param {DomNode} node node to iterate children of.
22434 * @param {Function} fn method of this class to call on each item.
22436 iterateChildren : function(node, fn)
22438 if (!node.childNodes.length) {
22441 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22442 fn.call(this, node.childNodes[i])
22448 * cleanTableWidths.
22450 * Quite often pasting from word etc.. results in tables with column and widths.
22451 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22454 cleanTableWidths : function(node)
22459 this.cleanTableWidths(this.doc.body);
22464 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22467 Roo.log(node.tagName);
22468 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22469 this.iterateChildren(node, this.cleanTableWidths);
22472 if (node.hasAttribute('width')) {
22473 node.removeAttribute('width');
22477 if (node.hasAttribute("style")) {
22480 var styles = node.getAttribute("style").split(";");
22482 Roo.each(styles, function(s) {
22483 if (!s.match(/:/)) {
22486 var kv = s.split(":");
22487 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22490 // what ever is left... we allow.
22493 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22494 if (!nstyle.length) {
22495 node.removeAttribute('style');
22499 this.iterateChildren(node, this.cleanTableWidths);
22507 domToHTML : function(currentElement, depth, nopadtext) {
22509 depth = depth || 0;
22510 nopadtext = nopadtext || false;
22512 if (!currentElement) {
22513 return this.domToHTML(this.doc.body);
22516 //Roo.log(currentElement);
22518 var allText = false;
22519 var nodeName = currentElement.nodeName;
22520 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22522 if (nodeName == '#text') {
22524 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22529 if (nodeName != 'BODY') {
22532 // Prints the node tagName, such as <A>, <IMG>, etc
22535 for(i = 0; i < currentElement.attributes.length;i++) {
22537 var aname = currentElement.attributes.item(i).name;
22538 if (!currentElement.attributes.item(i).value.length) {
22541 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22544 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22553 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22556 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22561 // Traverse the tree
22563 var currentElementChild = currentElement.childNodes.item(i);
22564 var allText = true;
22565 var innerHTML = '';
22567 while (currentElementChild) {
22568 // Formatting code (indent the tree so it looks nice on the screen)
22569 var nopad = nopadtext;
22570 if (lastnode == 'SPAN') {
22574 if (currentElementChild.nodeName == '#text') {
22575 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22576 toadd = nopadtext ? toadd : toadd.trim();
22577 if (!nopad && toadd.length > 80) {
22578 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22580 innerHTML += toadd;
22583 currentElementChild = currentElement.childNodes.item(i);
22589 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22591 // Recursively traverse the tree structure of the child node
22592 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22593 lastnode = currentElementChild.nodeName;
22595 currentElementChild=currentElement.childNodes.item(i);
22601 // The remaining code is mostly for formatting the tree
22602 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22607 ret+= "</"+tagName+">";
22613 applyBlacklists : function()
22615 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22616 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22620 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22621 if (b.indexOf(tag) > -1) {
22624 this.white.push(tag);
22628 Roo.each(w, function(tag) {
22629 if (b.indexOf(tag) > -1) {
22632 if (this.white.indexOf(tag) > -1) {
22635 this.white.push(tag);
22640 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22641 if (w.indexOf(tag) > -1) {
22644 this.black.push(tag);
22648 Roo.each(b, function(tag) {
22649 if (w.indexOf(tag) > -1) {
22652 if (this.black.indexOf(tag) > -1) {
22655 this.black.push(tag);
22660 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22661 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22665 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22666 if (b.indexOf(tag) > -1) {
22669 this.cwhite.push(tag);
22673 Roo.each(w, function(tag) {
22674 if (b.indexOf(tag) > -1) {
22677 if (this.cwhite.indexOf(tag) > -1) {
22680 this.cwhite.push(tag);
22685 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22686 if (w.indexOf(tag) > -1) {
22689 this.cblack.push(tag);
22693 Roo.each(b, function(tag) {
22694 if (w.indexOf(tag) > -1) {
22697 if (this.cblack.indexOf(tag) > -1) {
22700 this.cblack.push(tag);
22705 setStylesheets : function(stylesheets)
22707 if(typeof(stylesheets) == 'string'){
22708 Roo.get(this.iframe.contentDocument.head).createChild({
22710 rel : 'stylesheet',
22719 Roo.each(stylesheets, function(s) {
22724 Roo.get(_this.iframe.contentDocument.head).createChild({
22726 rel : 'stylesheet',
22735 removeStylesheets : function()
22739 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22744 setStyle : function(style)
22746 Roo.get(this.iframe.contentDocument.head).createChild({
22755 // hide stuff that is not compatible
22769 * @event specialkey
22773 * @cfg {String} fieldClass @hide
22776 * @cfg {String} focusClass @hide
22779 * @cfg {String} autoCreate @hide
22782 * @cfg {String} inputType @hide
22785 * @cfg {String} invalidClass @hide
22788 * @cfg {String} invalidText @hide
22791 * @cfg {String} msgFx @hide
22794 * @cfg {String} validateOnBlur @hide
22798 Roo.HtmlEditorCore.white = [
22799 'area', 'br', 'img', 'input', 'hr', 'wbr',
22801 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22802 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22803 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22804 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22805 'table', 'ul', 'xmp',
22807 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22810 'dir', 'menu', 'ol', 'ul', 'dl',
22816 Roo.HtmlEditorCore.black = [
22817 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22819 'base', 'basefont', 'bgsound', 'blink', 'body',
22820 'frame', 'frameset', 'head', 'html', 'ilayer',
22821 'iframe', 'layer', 'link', 'meta', 'object',
22822 'script', 'style' ,'title', 'xml' // clean later..
22824 Roo.HtmlEditorCore.clean = [
22825 'script', 'style', 'title', 'xml'
22827 Roo.HtmlEditorCore.remove = [
22832 Roo.HtmlEditorCore.ablack = [
22836 Roo.HtmlEditorCore.aclean = [
22837 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22841 Roo.HtmlEditorCore.pwhite= [
22842 'http', 'https', 'mailto'
22845 // white listed style attributes.
22846 Roo.HtmlEditorCore.cwhite= [
22847 // 'text-align', /// default is to allow most things..
22853 // black listed style attributes.
22854 Roo.HtmlEditorCore.cblack= [
22855 // 'font-size' -- this can be set by the project
22859 Roo.HtmlEditorCore.swapCodes =[
22878 * @class Roo.bootstrap.HtmlEditor
22879 * @extends Roo.bootstrap.TextArea
22880 * Bootstrap HtmlEditor class
22883 * Create a new HtmlEditor
22884 * @param {Object} config The config object
22887 Roo.bootstrap.HtmlEditor = function(config){
22888 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22889 if (!this.toolbars) {
22890 this.toolbars = [];
22893 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22896 * @event initialize
22897 * Fires when the editor is fully initialized (including the iframe)
22898 * @param {HtmlEditor} this
22903 * Fires when the editor is first receives the focus. Any insertion must wait
22904 * until after this event.
22905 * @param {HtmlEditor} this
22909 * @event beforesync
22910 * Fires before the textarea is updated with content from the editor iframe. Return false
22911 * to cancel the sync.
22912 * @param {HtmlEditor} this
22913 * @param {String} html
22917 * @event beforepush
22918 * Fires before the iframe editor is updated with content from the textarea. Return false
22919 * to cancel the push.
22920 * @param {HtmlEditor} this
22921 * @param {String} html
22926 * Fires when the textarea is updated with content from the editor iframe.
22927 * @param {HtmlEditor} this
22928 * @param {String} html
22933 * Fires when the iframe editor is updated with content from the textarea.
22934 * @param {HtmlEditor} this
22935 * @param {String} html
22939 * @event editmodechange
22940 * Fires when the editor switches edit modes
22941 * @param {HtmlEditor} this
22942 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22944 editmodechange: true,
22946 * @event editorevent
22947 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22948 * @param {HtmlEditor} this
22952 * @event firstfocus
22953 * Fires when on first focus - needed by toolbars..
22954 * @param {HtmlEditor} this
22959 * Auto save the htmlEditor value as a file into Events
22960 * @param {HtmlEditor} this
22964 * @event savedpreview
22965 * preview the saved version of htmlEditor
22966 * @param {HtmlEditor} this
22973 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22977 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22982 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
22987 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22992 * @cfg {Number} height (in pixels)
22996 * @cfg {Number} width (in pixels)
23001 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23004 stylesheets: false,
23009 // private properties
23010 validationEvent : false,
23012 initialized : false,
23015 onFocus : Roo.emptyFn,
23017 hideMode:'offsets',
23019 tbContainer : false,
23023 toolbarContainer :function() {
23024 return this.wrap.select('.x-html-editor-tb',true).first();
23028 * Protected method that will not generally be called directly. It
23029 * is called when the editor creates its toolbar. Override this method if you need to
23030 * add custom toolbar buttons.
23031 * @param {HtmlEditor} editor
23033 createToolbar : function(){
23034 Roo.log('renewing');
23035 Roo.log("create toolbars");
23037 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23038 this.toolbars[0].render(this.toolbarContainer());
23042 // if (!editor.toolbars || !editor.toolbars.length) {
23043 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23046 // for (var i =0 ; i < editor.toolbars.length;i++) {
23047 // editor.toolbars[i] = Roo.factory(
23048 // typeof(editor.toolbars[i]) == 'string' ?
23049 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23050 // Roo.bootstrap.HtmlEditor);
23051 // editor.toolbars[i].init(editor);
23057 onRender : function(ct, position)
23059 // Roo.log("Call onRender: " + this.xtype);
23061 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23063 this.wrap = this.inputEl().wrap({
23064 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23067 this.editorcore.onRender(ct, position);
23069 if (this.resizable) {
23070 this.resizeEl = new Roo.Resizable(this.wrap, {
23074 minHeight : this.height,
23075 height: this.height,
23076 handles : this.resizable,
23079 resize : function(r, w, h) {
23080 _t.onResize(w,h); // -something
23086 this.createToolbar(this);
23089 if(!this.width && this.resizable){
23090 this.setSize(this.wrap.getSize());
23092 if (this.resizeEl) {
23093 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23094 // should trigger onReize..
23100 onResize : function(w, h)
23102 Roo.log('resize: ' +w + ',' + h );
23103 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23107 if(this.inputEl() ){
23108 if(typeof w == 'number'){
23109 var aw = w - this.wrap.getFrameWidth('lr');
23110 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23113 if(typeof h == 'number'){
23114 var tbh = -11; // fixme it needs to tool bar size!
23115 for (var i =0; i < this.toolbars.length;i++) {
23116 // fixme - ask toolbars for heights?
23117 tbh += this.toolbars[i].el.getHeight();
23118 //if (this.toolbars[i].footer) {
23119 // tbh += this.toolbars[i].footer.el.getHeight();
23127 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23128 ah -= 5; // knock a few pixes off for look..
23129 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23133 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23134 this.editorcore.onResize(ew,eh);
23139 * Toggles the editor between standard and source edit mode.
23140 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23142 toggleSourceEdit : function(sourceEditMode)
23144 this.editorcore.toggleSourceEdit(sourceEditMode);
23146 if(this.editorcore.sourceEditMode){
23147 Roo.log('editor - showing textarea');
23150 // Roo.log(this.syncValue());
23152 this.inputEl().removeClass(['hide', 'x-hidden']);
23153 this.inputEl().dom.removeAttribute('tabIndex');
23154 this.inputEl().focus();
23156 Roo.log('editor - hiding textarea');
23158 // Roo.log(this.pushValue());
23161 this.inputEl().addClass(['hide', 'x-hidden']);
23162 this.inputEl().dom.setAttribute('tabIndex', -1);
23163 //this.deferFocus();
23166 if(this.resizable){
23167 this.setSize(this.wrap.getSize());
23170 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23173 // private (for BoxComponent)
23174 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23176 // private (for BoxComponent)
23177 getResizeEl : function(){
23181 // private (for BoxComponent)
23182 getPositionEl : function(){
23187 initEvents : function(){
23188 this.originalValue = this.getValue();
23192 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23195 // markInvalid : Roo.emptyFn,
23197 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23200 // clearInvalid : Roo.emptyFn,
23202 setValue : function(v){
23203 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23204 this.editorcore.pushValue();
23209 deferFocus : function(){
23210 this.focus.defer(10, this);
23214 focus : function(){
23215 this.editorcore.focus();
23221 onDestroy : function(){
23227 for (var i =0; i < this.toolbars.length;i++) {
23228 // fixme - ask toolbars for heights?
23229 this.toolbars[i].onDestroy();
23232 this.wrap.dom.innerHTML = '';
23233 this.wrap.remove();
23238 onFirstFocus : function(){
23239 //Roo.log("onFirstFocus");
23240 this.editorcore.onFirstFocus();
23241 for (var i =0; i < this.toolbars.length;i++) {
23242 this.toolbars[i].onFirstFocus();
23248 syncValue : function()
23250 this.editorcore.syncValue();
23253 pushValue : function()
23255 this.editorcore.pushValue();
23259 // hide stuff that is not compatible
23273 * @event specialkey
23277 * @cfg {String} fieldClass @hide
23280 * @cfg {String} focusClass @hide
23283 * @cfg {String} autoCreate @hide
23286 * @cfg {String} inputType @hide
23289 * @cfg {String} invalidClass @hide
23292 * @cfg {String} invalidText @hide
23295 * @cfg {String} msgFx @hide
23298 * @cfg {String} validateOnBlur @hide
23307 Roo.namespace('Roo.bootstrap.htmleditor');
23309 * @class Roo.bootstrap.HtmlEditorToolbar1
23314 new Roo.bootstrap.HtmlEditor({
23317 new Roo.bootstrap.HtmlEditorToolbar1({
23318 disable : { fonts: 1 , format: 1, ..., ... , ...],
23324 * @cfg {Object} disable List of elements to disable..
23325 * @cfg {Array} btns List of additional buttons.
23329 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23332 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23335 Roo.apply(this, config);
23337 // default disabled, based on 'good practice'..
23338 this.disable = this.disable || {};
23339 Roo.applyIf(this.disable, {
23342 specialElements : true
23344 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23346 this.editor = config.editor;
23347 this.editorcore = config.editor.editorcore;
23349 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23351 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23352 // dont call parent... till later.
23354 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23359 editorcore : false,
23364 "h1","h2","h3","h4","h5","h6",
23366 "abbr", "acronym", "address", "cite", "samp", "var",
23370 onRender : function(ct, position)
23372 // Roo.log("Call onRender: " + this.xtype);
23374 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23376 this.el.dom.style.marginBottom = '0';
23378 var editorcore = this.editorcore;
23379 var editor= this.editor;
23382 var btn = function(id,cmd , toggle, handler, html){
23384 var event = toggle ? 'toggle' : 'click';
23389 xns: Roo.bootstrap,
23392 enableToggle:toggle !== false,
23394 pressed : toggle ? false : null,
23397 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23398 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23404 // var cb_box = function...
23409 xns: Roo.bootstrap,
23410 glyphicon : 'font',
23414 xns: Roo.bootstrap,
23418 Roo.each(this.formats, function(f) {
23419 style.menu.items.push({
23421 xns: Roo.bootstrap,
23422 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23427 editorcore.insertTag(this.tagname);
23434 children.push(style);
23436 btn('bold',false,true);
23437 btn('italic',false,true);
23438 btn('align-left', 'justifyleft',true);
23439 btn('align-center', 'justifycenter',true);
23440 btn('align-right' , 'justifyright',true);
23441 btn('link', false, false, function(btn) {
23442 //Roo.log("create link?");
23443 var url = prompt(this.createLinkText, this.defaultLinkValue);
23444 if(url && url != 'http:/'+'/'){
23445 this.editorcore.relayCmd('createlink', url);
23448 btn('list','insertunorderedlist',true);
23449 btn('pencil', false,true, function(btn){
23451 this.toggleSourceEdit(btn.pressed);
23454 if (this.editor.btns.length > 0) {
23455 for (var i = 0; i<this.editor.btns.length; i++) {
23456 children.push(this.editor.btns[i]);
23464 xns: Roo.bootstrap,
23469 xns: Roo.bootstrap,
23474 cog.menu.items.push({
23476 xns: Roo.bootstrap,
23477 html : Clean styles,
23482 editorcore.insertTag(this.tagname);
23491 this.xtype = 'NavSimplebar';
23493 for(var i=0;i< children.length;i++) {
23495 this.buttons.add(this.addxtypeChild(children[i]));
23499 editor.on('editorevent', this.updateToolbar, this);
23501 onBtnClick : function(id)
23503 this.editorcore.relayCmd(id);
23504 this.editorcore.focus();
23508 * Protected method that will not generally be called directly. It triggers
23509 * a toolbar update by reading the markup state of the current selection in the editor.
23511 updateToolbar: function(){
23513 if(!this.editorcore.activated){
23514 this.editor.onFirstFocus(); // is this neeed?
23518 var btns = this.buttons;
23519 var doc = this.editorcore.doc;
23520 btns.get('bold').setActive(doc.queryCommandState('bold'));
23521 btns.get('italic').setActive(doc.queryCommandState('italic'));
23522 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23524 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23525 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23526 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23528 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23529 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23532 var ans = this.editorcore.getAllAncestors();
23533 if (this.formatCombo) {
23536 var store = this.formatCombo.store;
23537 this.formatCombo.setValue("");
23538 for (var i =0; i < ans.length;i++) {
23539 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23541 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23549 // hides menus... - so this cant be on a menu...
23550 Roo.bootstrap.MenuMgr.hideAll();
23552 Roo.bootstrap.MenuMgr.hideAll();
23553 //this.editorsyncValue();
23555 onFirstFocus: function() {
23556 this.buttons.each(function(item){
23560 toggleSourceEdit : function(sourceEditMode){
23563 if(sourceEditMode){
23564 Roo.log("disabling buttons");
23565 this.buttons.each( function(item){
23566 if(item.cmd != 'pencil'){
23572 Roo.log("enabling buttons");
23573 if(this.editorcore.initialized){
23574 this.buttons.each( function(item){
23580 Roo.log("calling toggole on editor");
23581 // tell the editor that it's been pressed..
23582 this.editor.toggleSourceEdit(sourceEditMode);
23592 * @class Roo.bootstrap.Table.AbstractSelectionModel
23593 * @extends Roo.util.Observable
23594 * Abstract base class for grid SelectionModels. It provides the interface that should be
23595 * implemented by descendant classes. This class should not be directly instantiated.
23598 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23599 this.locked = false;
23600 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23604 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23605 /** @ignore Called by the grid automatically. Do not call directly. */
23606 init : function(grid){
23612 * Locks the selections.
23615 this.locked = true;
23619 * Unlocks the selections.
23621 unlock : function(){
23622 this.locked = false;
23626 * Returns true if the selections are locked.
23627 * @return {Boolean}
23629 isLocked : function(){
23630 return this.locked;
23634 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23635 * @class Roo.bootstrap.Table.RowSelectionModel
23636 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23637 * It supports multiple selections and keyboard selection/navigation.
23639 * @param {Object} config
23642 Roo.bootstrap.Table.RowSelectionModel = function(config){
23643 Roo.apply(this, config);
23644 this.selections = new Roo.util.MixedCollection(false, function(o){
23649 this.lastActive = false;
23653 * @event selectionchange
23654 * Fires when the selection changes
23655 * @param {SelectionModel} this
23657 "selectionchange" : true,
23659 * @event afterselectionchange
23660 * Fires after the selection changes (eg. by key press or clicking)
23661 * @param {SelectionModel} this
23663 "afterselectionchange" : true,
23665 * @event beforerowselect
23666 * Fires when a row is selected being selected, return false to cancel.
23667 * @param {SelectionModel} this
23668 * @param {Number} rowIndex The selected index
23669 * @param {Boolean} keepExisting False if other selections will be cleared
23671 "beforerowselect" : true,
23674 * Fires when a row is selected.
23675 * @param {SelectionModel} this
23676 * @param {Number} rowIndex The selected index
23677 * @param {Roo.data.Record} r The record
23679 "rowselect" : true,
23681 * @event rowdeselect
23682 * Fires when a row is deselected.
23683 * @param {SelectionModel} this
23684 * @param {Number} rowIndex The selected index
23686 "rowdeselect" : true
23688 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23689 this.locked = false;
23692 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23694 * @cfg {Boolean} singleSelect
23695 * True to allow selection of only one row at a time (defaults to false)
23697 singleSelect : false,
23700 initEvents : function()
23703 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23704 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23705 //}else{ // allow click to work like normal
23706 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23708 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23709 this.grid.on("rowclick", this.handleMouseDown, this);
23711 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23712 "up" : function(e){
23714 this.selectPrevious(e.shiftKey);
23715 }else if(this.last !== false && this.lastActive !== false){
23716 var last = this.last;
23717 this.selectRange(this.last, this.lastActive-1);
23718 this.grid.getView().focusRow(this.lastActive);
23719 if(last !== false){
23723 this.selectFirstRow();
23725 this.fireEvent("afterselectionchange", this);
23727 "down" : function(e){
23729 this.selectNext(e.shiftKey);
23730 }else if(this.last !== false && this.lastActive !== false){
23731 var last = this.last;
23732 this.selectRange(this.last, this.lastActive+1);
23733 this.grid.getView().focusRow(this.lastActive);
23734 if(last !== false){
23738 this.selectFirstRow();
23740 this.fireEvent("afterselectionchange", this);
23744 this.grid.store.on('load', function(){
23745 this.selections.clear();
23748 var view = this.grid.view;
23749 view.on("refresh", this.onRefresh, this);
23750 view.on("rowupdated", this.onRowUpdated, this);
23751 view.on("rowremoved", this.onRemove, this);
23756 onRefresh : function()
23758 var ds = this.grid.store, i, v = this.grid.view;
23759 var s = this.selections;
23760 s.each(function(r){
23761 if((i = ds.indexOfId(r.id)) != -1){
23770 onRemove : function(v, index, r){
23771 this.selections.remove(r);
23775 onRowUpdated : function(v, index, r){
23776 if(this.isSelected(r)){
23777 v.onRowSelect(index);
23783 * @param {Array} records The records to select
23784 * @param {Boolean} keepExisting (optional) True to keep existing selections
23786 selectRecords : function(records, keepExisting)
23789 this.clearSelections();
23791 var ds = this.grid.store;
23792 for(var i = 0, len = records.length; i < len; i++){
23793 this.selectRow(ds.indexOf(records[i]), true);
23798 * Gets the number of selected rows.
23801 getCount : function(){
23802 return this.selections.length;
23806 * Selects the first row in the grid.
23808 selectFirstRow : function(){
23813 * Select the last row.
23814 * @param {Boolean} keepExisting (optional) True to keep existing selections
23816 selectLastRow : function(keepExisting){
23817 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23818 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23822 * Selects the row immediately following the last selected row.
23823 * @param {Boolean} keepExisting (optional) True to keep existing selections
23825 selectNext : function(keepExisting)
23827 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23828 this.selectRow(this.last+1, keepExisting);
23829 this.grid.getView().focusRow(this.last);
23834 * Selects the row that precedes the last selected row.
23835 * @param {Boolean} keepExisting (optional) True to keep existing selections
23837 selectPrevious : function(keepExisting){
23839 this.selectRow(this.last-1, keepExisting);
23840 this.grid.getView().focusRow(this.last);
23845 * Returns the selected records
23846 * @return {Array} Array of selected records
23848 getSelections : function(){
23849 return [].concat(this.selections.items);
23853 * Returns the first selected record.
23856 getSelected : function(){
23857 return this.selections.itemAt(0);
23862 * Clears all selections.
23864 clearSelections : function(fast)
23870 var ds = this.grid.store;
23871 var s = this.selections;
23872 s.each(function(r){
23873 this.deselectRow(ds.indexOfId(r.id));
23877 this.selections.clear();
23884 * Selects all rows.
23886 selectAll : function(){
23890 this.selections.clear();
23891 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23892 this.selectRow(i, true);
23897 * Returns True if there is a selection.
23898 * @return {Boolean}
23900 hasSelection : function(){
23901 return this.selections.length > 0;
23905 * Returns True if the specified row is selected.
23906 * @param {Number/Record} record The record or index of the record to check
23907 * @return {Boolean}
23909 isSelected : function(index){
23910 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23911 return (r && this.selections.key(r.id) ? true : false);
23915 * Returns True if the specified record id is selected.
23916 * @param {String} id The id of record to check
23917 * @return {Boolean}
23919 isIdSelected : function(id){
23920 return (this.selections.key(id) ? true : false);
23925 handleMouseDBClick : function(e, t){
23929 handleMouseDown : function(e, t)
23931 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23932 if(this.isLocked() || rowIndex < 0 ){
23935 if(e.shiftKey && this.last !== false){
23936 var last = this.last;
23937 this.selectRange(last, rowIndex, e.ctrlKey);
23938 this.last = last; // reset the last
23942 var isSelected = this.isSelected(rowIndex);
23943 //Roo.log("select row:" + rowIndex);
23945 this.deselectRow(rowIndex);
23947 this.selectRow(rowIndex, true);
23951 if(e.button !== 0 && isSelected){
23952 alert('rowIndex 2: ' + rowIndex);
23953 view.focusRow(rowIndex);
23954 }else if(e.ctrlKey && isSelected){
23955 this.deselectRow(rowIndex);
23956 }else if(!isSelected){
23957 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23958 view.focusRow(rowIndex);
23962 this.fireEvent("afterselectionchange", this);
23965 handleDragableRowClick : function(grid, rowIndex, e)
23967 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23968 this.selectRow(rowIndex, false);
23969 grid.view.focusRow(rowIndex);
23970 this.fireEvent("afterselectionchange", this);
23975 * Selects multiple rows.
23976 * @param {Array} rows Array of the indexes of the row to select
23977 * @param {Boolean} keepExisting (optional) True to keep existing selections
23979 selectRows : function(rows, keepExisting){
23981 this.clearSelections();
23983 for(var i = 0, len = rows.length; i < len; i++){
23984 this.selectRow(rows[i], true);
23989 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23990 * @param {Number} startRow The index of the first row in the range
23991 * @param {Number} endRow The index of the last row in the range
23992 * @param {Boolean} keepExisting (optional) True to retain existing selections
23994 selectRange : function(startRow, endRow, keepExisting){
23999 this.clearSelections();
24001 if(startRow <= endRow){
24002 for(var i = startRow; i <= endRow; i++){
24003 this.selectRow(i, true);
24006 for(var i = startRow; i >= endRow; i--){
24007 this.selectRow(i, true);
24013 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24014 * @param {Number} startRow The index of the first row in the range
24015 * @param {Number} endRow The index of the last row in the range
24017 deselectRange : function(startRow, endRow, preventViewNotify){
24021 for(var i = startRow; i <= endRow; i++){
24022 this.deselectRow(i, preventViewNotify);
24028 * @param {Number} row The index of the row to select
24029 * @param {Boolean} keepExisting (optional) True to keep existing selections
24031 selectRow : function(index, keepExisting, preventViewNotify)
24033 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24036 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24037 if(!keepExisting || this.singleSelect){
24038 this.clearSelections();
24041 var r = this.grid.store.getAt(index);
24042 //console.log('selectRow - record id :' + r.id);
24044 this.selections.add(r);
24045 this.last = this.lastActive = index;
24046 if(!preventViewNotify){
24047 var proxy = new Roo.Element(
24048 this.grid.getRowDom(index)
24050 proxy.addClass('bg-info info');
24052 this.fireEvent("rowselect", this, index, r);
24053 this.fireEvent("selectionchange", this);
24059 * @param {Number} row The index of the row to deselect
24061 deselectRow : function(index, preventViewNotify)
24066 if(this.last == index){
24069 if(this.lastActive == index){
24070 this.lastActive = false;
24073 var r = this.grid.store.getAt(index);
24078 this.selections.remove(r);
24079 //.console.log('deselectRow - record id :' + r.id);
24080 if(!preventViewNotify){
24082 var proxy = new Roo.Element(
24083 this.grid.getRowDom(index)
24085 proxy.removeClass('bg-info info');
24087 this.fireEvent("rowdeselect", this, index);
24088 this.fireEvent("selectionchange", this);
24092 restoreLast : function(){
24094 this.last = this._last;
24099 acceptsNav : function(row, col, cm){
24100 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24104 onEditorKey : function(field, e){
24105 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24110 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24112 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24114 }else if(k == e.ENTER && !e.ctrlKey){
24118 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24120 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24122 }else if(k == e.ESC){
24126 g.startEditing(newCell[0], newCell[1]);
24132 * Ext JS Library 1.1.1
24133 * Copyright(c) 2006-2007, Ext JS, LLC.
24135 * Originally Released Under LGPL - original licence link has changed is not relivant.
24138 * <script type="text/javascript">
24142 * @class Roo.bootstrap.PagingToolbar
24143 * @extends Roo.bootstrap.NavSimplebar
24144 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24146 * Create a new PagingToolbar
24147 * @param {Object} config The config object
24148 * @param {Roo.data.Store} store
24150 Roo.bootstrap.PagingToolbar = function(config)
24152 // old args format still supported... - xtype is prefered..
24153 // created from xtype...
24155 this.ds = config.dataSource;
24157 if (config.store && !this.ds) {
24158 this.store= Roo.factory(config.store, Roo.data);
24159 this.ds = this.store;
24160 this.ds.xmodule = this.xmodule || false;
24163 this.toolbarItems = [];
24164 if (config.items) {
24165 this.toolbarItems = config.items;
24168 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24173 this.bind(this.ds);
24176 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24180 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24182 * @cfg {Roo.data.Store} dataSource
24183 * The underlying data store providing the paged data
24186 * @cfg {String/HTMLElement/Element} container
24187 * container The id or element that will contain the toolbar
24190 * @cfg {Boolean} displayInfo
24191 * True to display the displayMsg (defaults to false)
24194 * @cfg {Number} pageSize
24195 * The number of records to display per page (defaults to 20)
24199 * @cfg {String} displayMsg
24200 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24202 displayMsg : 'Displaying {0} - {1} of {2}',
24204 * @cfg {String} emptyMsg
24205 * The message to display when no records are found (defaults to "No data to display")
24207 emptyMsg : 'No data to display',
24209 * Customizable piece of the default paging text (defaults to "Page")
24212 beforePageText : "Page",
24214 * Customizable piece of the default paging text (defaults to "of %0")
24217 afterPageText : "of {0}",
24219 * Customizable piece of the default paging text (defaults to "First Page")
24222 firstText : "First Page",
24224 * Customizable piece of the default paging text (defaults to "Previous Page")
24227 prevText : "Previous Page",
24229 * Customizable piece of the default paging text (defaults to "Next Page")
24232 nextText : "Next Page",
24234 * Customizable piece of the default paging text (defaults to "Last Page")
24237 lastText : "Last Page",
24239 * Customizable piece of the default paging text (defaults to "Refresh")
24242 refreshText : "Refresh",
24246 onRender : function(ct, position)
24248 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24249 this.navgroup.parentId = this.id;
24250 this.navgroup.onRender(this.el, null);
24251 // add the buttons to the navgroup
24253 if(this.displayInfo){
24254 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24255 this.displayEl = this.el.select('.x-paging-info', true).first();
24256 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24257 // this.displayEl = navel.el.select('span',true).first();
24263 Roo.each(_this.buttons, function(e){ // this might need to use render????
24264 Roo.factory(e).onRender(_this.el, null);
24268 Roo.each(_this.toolbarItems, function(e) {
24269 _this.navgroup.addItem(e);
24273 this.first = this.navgroup.addItem({
24274 tooltip: this.firstText,
24276 icon : 'fa fa-backward',
24278 preventDefault: true,
24279 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24282 this.prev = this.navgroup.addItem({
24283 tooltip: this.prevText,
24285 icon : 'fa fa-step-backward',
24287 preventDefault: true,
24288 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24290 //this.addSeparator();
24293 var field = this.navgroup.addItem( {
24295 cls : 'x-paging-position',
24297 html : this.beforePageText +
24298 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24299 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24302 this.field = field.el.select('input', true).first();
24303 this.field.on("keydown", this.onPagingKeydown, this);
24304 this.field.on("focus", function(){this.dom.select();});
24307 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24308 //this.field.setHeight(18);
24309 //this.addSeparator();
24310 this.next = this.navgroup.addItem({
24311 tooltip: this.nextText,
24313 html : ' <i class="fa fa-step-forward">',
24315 preventDefault: true,
24316 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24318 this.last = this.navgroup.addItem({
24319 tooltip: this.lastText,
24320 icon : 'fa fa-forward',
24323 preventDefault: true,
24324 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24326 //this.addSeparator();
24327 this.loading = this.navgroup.addItem({
24328 tooltip: this.refreshText,
24329 icon: 'fa fa-refresh',
24330 preventDefault: true,
24331 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24337 updateInfo : function(){
24338 if(this.displayEl){
24339 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24340 var msg = count == 0 ?
24344 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24346 this.displayEl.update(msg);
24351 onLoad : function(ds, r, o)
24353 this.cursor = o.params ? o.params.start : 0;
24354 var d = this.getPageData(),
24359 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24360 this.field.dom.value = ap;
24361 this.first.setDisabled(ap == 1);
24362 this.prev.setDisabled(ap == 1);
24363 this.next.setDisabled(ap == ps);
24364 this.last.setDisabled(ap == ps);
24365 this.loading.enable();
24370 getPageData : function(){
24371 var total = this.ds.getTotalCount();
24374 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24375 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24380 onLoadError : function(){
24381 this.loading.enable();
24385 onPagingKeydown : function(e){
24386 var k = e.getKey();
24387 var d = this.getPageData();
24389 var v = this.field.dom.value, pageNum;
24390 if(!v || isNaN(pageNum = parseInt(v, 10))){
24391 this.field.dom.value = d.activePage;
24394 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24395 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24398 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))
24400 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24401 this.field.dom.value = pageNum;
24402 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24405 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24407 var v = this.field.dom.value, pageNum;
24408 var increment = (e.shiftKey) ? 10 : 1;
24409 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24412 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24413 this.field.dom.value = d.activePage;
24416 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24418 this.field.dom.value = parseInt(v, 10) + increment;
24419 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24420 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24427 beforeLoad : function(){
24429 this.loading.disable();
24434 onClick : function(which){
24443 ds.load({params:{start: 0, limit: this.pageSize}});
24446 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24449 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24452 var total = ds.getTotalCount();
24453 var extra = total % this.pageSize;
24454 var lastStart = extra ? (total - extra) : total-this.pageSize;
24455 ds.load({params:{start: lastStart, limit: this.pageSize}});
24458 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24464 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24465 * @param {Roo.data.Store} store The data store to unbind
24467 unbind : function(ds){
24468 ds.un("beforeload", this.beforeLoad, this);
24469 ds.un("load", this.onLoad, this);
24470 ds.un("loadexception", this.onLoadError, this);
24471 ds.un("remove", this.updateInfo, this);
24472 ds.un("add", this.updateInfo, this);
24473 this.ds = undefined;
24477 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24478 * @param {Roo.data.Store} store The data store to bind
24480 bind : function(ds){
24481 ds.on("beforeload", this.beforeLoad, this);
24482 ds.on("load", this.onLoad, this);
24483 ds.on("loadexception", this.onLoadError, this);
24484 ds.on("remove", this.updateInfo, this);
24485 ds.on("add", this.updateInfo, this);
24496 * @class Roo.bootstrap.MessageBar
24497 * @extends Roo.bootstrap.Component
24498 * Bootstrap MessageBar class
24499 * @cfg {String} html contents of the MessageBar
24500 * @cfg {String} weight (info | success | warning | danger) default info
24501 * @cfg {String} beforeClass insert the bar before the given class
24502 * @cfg {Boolean} closable (true | false) default false
24503 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24506 * Create a new Element
24507 * @param {Object} config The config object
24510 Roo.bootstrap.MessageBar = function(config){
24511 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24514 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24520 beforeClass: 'bootstrap-sticky-wrap',
24522 getAutoCreate : function(){
24526 cls: 'alert alert-dismissable alert-' + this.weight,
24531 html: this.html || ''
24537 cfg.cls += ' alert-messages-fixed';
24551 onRender : function(ct, position)
24553 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24556 var cfg = Roo.apply({}, this.getAutoCreate());
24560 cfg.cls += ' ' + this.cls;
24563 cfg.style = this.style;
24565 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24567 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24570 this.el.select('>button.close').on('click', this.hide, this);
24576 if (!this.rendered) {
24582 this.fireEvent('show', this);
24588 if (!this.rendered) {
24594 this.fireEvent('hide', this);
24597 update : function()
24599 // var e = this.el.dom.firstChild;
24601 // if(this.closable){
24602 // e = e.nextSibling;
24605 // e.data = this.html || '';
24607 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24623 * @class Roo.bootstrap.Graph
24624 * @extends Roo.bootstrap.Component
24625 * Bootstrap Graph class
24629 @cfg {String} graphtype bar | vbar | pie
24630 @cfg {number} g_x coodinator | centre x (pie)
24631 @cfg {number} g_y coodinator | centre y (pie)
24632 @cfg {number} g_r radius (pie)
24633 @cfg {number} g_height height of the chart (respected by all elements in the set)
24634 @cfg {number} g_width width of the chart (respected by all elements in the set)
24635 @cfg {Object} title The title of the chart
24638 -opts (object) options for the chart
24640 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24641 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24643 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.
24644 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24646 o stretch (boolean)
24648 -opts (object) options for the pie
24651 o startAngle (number)
24652 o endAngle (number)
24656 * Create a new Input
24657 * @param {Object} config The config object
24660 Roo.bootstrap.Graph = function(config){
24661 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24667 * The img click event for the img.
24668 * @param {Roo.EventObject} e
24674 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24685 //g_colors: this.colors,
24692 getAutoCreate : function(){
24703 onRender : function(ct,position){
24706 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24708 if (typeof(Raphael) == 'undefined') {
24709 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24713 this.raphael = Raphael(this.el.dom);
24715 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24716 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24717 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24718 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24720 r.text(160, 10, "Single Series Chart").attr(txtattr);
24721 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24722 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24723 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24725 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24726 r.barchart(330, 10, 300, 220, data1);
24727 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24728 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24731 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24732 // r.barchart(30, 30, 560, 250, xdata, {
24733 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24734 // axis : "0 0 1 1",
24735 // axisxlabels : xdata
24736 // //yvalues : cols,
24739 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24741 // this.load(null,xdata,{
24742 // axis : "0 0 1 1",
24743 // axisxlabels : xdata
24748 load : function(graphtype,xdata,opts)
24750 this.raphael.clear();
24752 graphtype = this.graphtype;
24757 var r = this.raphael,
24758 fin = function () {
24759 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24761 fout = function () {
24762 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24764 pfin = function() {
24765 this.sector.stop();
24766 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24769 this.label[0].stop();
24770 this.label[0].attr({ r: 7.5 });
24771 this.label[1].attr({ "font-weight": 800 });
24774 pfout = function() {
24775 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24778 this.label[0].animate({ r: 5 }, 500, "bounce");
24779 this.label[1].attr({ "font-weight": 400 });
24785 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24788 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24791 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24792 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24794 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24801 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24806 setTitle: function(o)
24811 initEvents: function() {
24814 this.el.on('click', this.onClick, this);
24818 onClick : function(e)
24820 Roo.log('img onclick');
24821 this.fireEvent('click', this, e);
24833 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24836 * @class Roo.bootstrap.dash.NumberBox
24837 * @extends Roo.bootstrap.Component
24838 * Bootstrap NumberBox class
24839 * @cfg {String} headline Box headline
24840 * @cfg {String} content Box content
24841 * @cfg {String} icon Box icon
24842 * @cfg {String} footer Footer text
24843 * @cfg {String} fhref Footer href
24846 * Create a new NumberBox
24847 * @param {Object} config The config object
24851 Roo.bootstrap.dash.NumberBox = function(config){
24852 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24856 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24865 getAutoCreate : function(){
24869 cls : 'small-box ',
24877 cls : 'roo-headline',
24878 html : this.headline
24882 cls : 'roo-content',
24883 html : this.content
24897 cls : 'ion ' + this.icon
24906 cls : 'small-box-footer',
24907 href : this.fhref || '#',
24911 cfg.cn.push(footer);
24918 onRender : function(ct,position){
24919 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24926 setHeadline: function (value)
24928 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24931 setFooter: function (value, href)
24933 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24936 this.el.select('a.small-box-footer',true).first().attr('href', href);
24941 setContent: function (value)
24943 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24946 initEvents: function()
24960 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24963 * @class Roo.bootstrap.dash.TabBox
24964 * @extends Roo.bootstrap.Component
24965 * Bootstrap TabBox class
24966 * @cfg {String} title Title of the TabBox
24967 * @cfg {String} icon Icon of the TabBox
24968 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24969 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24972 * Create a new TabBox
24973 * @param {Object} config The config object
24977 Roo.bootstrap.dash.TabBox = function(config){
24978 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24983 * When a pane is added
24984 * @param {Roo.bootstrap.dash.TabPane} pane
24988 * @event activatepane
24989 * When a pane is activated
24990 * @param {Roo.bootstrap.dash.TabPane} pane
24992 "activatepane" : true
25000 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25005 tabScrollable : false,
25007 getChildContainer : function()
25009 return this.el.select('.tab-content', true).first();
25012 getAutoCreate : function(){
25016 cls: 'pull-left header',
25024 cls: 'fa ' + this.icon
25030 cls: 'nav nav-tabs pull-right',
25036 if(this.tabScrollable){
25043 cls: 'nav nav-tabs pull-right',
25054 cls: 'nav-tabs-custom',
25059 cls: 'tab-content no-padding',
25067 initEvents : function()
25069 //Roo.log('add add pane handler');
25070 this.on('addpane', this.onAddPane, this);
25073 * Updates the box title
25074 * @param {String} html to set the title to.
25076 setTitle : function(value)
25078 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25080 onAddPane : function(pane)
25082 this.panes.push(pane);
25083 //Roo.log('addpane');
25085 // tabs are rendere left to right..
25086 if(!this.showtabs){
25090 var ctr = this.el.select('.nav-tabs', true).first();
25093 var existing = ctr.select('.nav-tab',true);
25094 var qty = existing.getCount();;
25097 var tab = ctr.createChild({
25099 cls : 'nav-tab' + (qty ? '' : ' active'),
25107 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25110 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25112 pane.el.addClass('active');
25117 onTabClick : function(ev,un,ob,pane)
25119 //Roo.log('tab - prev default');
25120 ev.preventDefault();
25123 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25124 pane.tab.addClass('active');
25125 //Roo.log(pane.title);
25126 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25127 // technically we should have a deactivate event.. but maybe add later.
25128 // and it should not de-activate the selected tab...
25129 this.fireEvent('activatepane', pane);
25130 pane.el.addClass('active');
25131 pane.fireEvent('activate');
25136 getActivePane : function()
25139 Roo.each(this.panes, function(p) {
25140 if(p.el.hasClass('active')){
25161 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25163 * @class Roo.bootstrap.TabPane
25164 * @extends Roo.bootstrap.Component
25165 * Bootstrap TabPane class
25166 * @cfg {Boolean} active (false | true) Default false
25167 * @cfg {String} title title of panel
25171 * Create a new TabPane
25172 * @param {Object} config The config object
25175 Roo.bootstrap.dash.TabPane = function(config){
25176 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25182 * When a pane is activated
25183 * @param {Roo.bootstrap.dash.TabPane} pane
25190 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25195 // the tabBox that this is attached to.
25198 getAutoCreate : function()
25206 cfg.cls += ' active';
25211 initEvents : function()
25213 //Roo.log('trigger add pane handler');
25214 this.parent().fireEvent('addpane', this)
25218 * Updates the tab title
25219 * @param {String} html to set the title to.
25221 setTitle: function(str)
25227 this.tab.select('a', true).first().dom.innerHTML = str;
25244 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25247 * @class Roo.bootstrap.menu.Menu
25248 * @extends Roo.bootstrap.Component
25249 * Bootstrap Menu class - container for Menu
25250 * @cfg {String} html Text of the menu
25251 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25252 * @cfg {String} icon Font awesome icon
25253 * @cfg {String} pos Menu align to (top | bottom) default bottom
25257 * Create a new Menu
25258 * @param {Object} config The config object
25262 Roo.bootstrap.menu.Menu = function(config){
25263 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25267 * @event beforeshow
25268 * Fires before this menu is displayed
25269 * @param {Roo.bootstrap.menu.Menu} this
25273 * @event beforehide
25274 * Fires before this menu is hidden
25275 * @param {Roo.bootstrap.menu.Menu} this
25280 * Fires after this menu is displayed
25281 * @param {Roo.bootstrap.menu.Menu} this
25286 * Fires after this menu is hidden
25287 * @param {Roo.bootstrap.menu.Menu} this
25292 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25293 * @param {Roo.bootstrap.menu.Menu} this
25294 * @param {Roo.EventObject} e
25301 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25305 weight : 'default',
25310 getChildContainer : function() {
25311 if(this.isSubMenu){
25315 return this.el.select('ul.dropdown-menu', true).first();
25318 getAutoCreate : function()
25323 cls : 'roo-menu-text',
25331 cls : 'fa ' + this.icon
25342 cls : 'dropdown-button btn btn-' + this.weight,
25347 cls : 'dropdown-toggle btn btn-' + this.weight,
25357 cls : 'dropdown-menu'
25363 if(this.pos == 'top'){
25364 cfg.cls += ' dropup';
25367 if(this.isSubMenu){
25370 cls : 'dropdown-menu'
25377 onRender : function(ct, position)
25379 this.isSubMenu = ct.hasClass('dropdown-submenu');
25381 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25384 initEvents : function()
25386 if(this.isSubMenu){
25390 this.hidden = true;
25392 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25393 this.triggerEl.on('click', this.onTriggerPress, this);
25395 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25396 this.buttonEl.on('click', this.onClick, this);
25402 if(this.isSubMenu){
25406 return this.el.select('ul.dropdown-menu', true).first();
25409 onClick : function(e)
25411 this.fireEvent("click", this, e);
25414 onTriggerPress : function(e)
25416 if (this.isVisible()) {
25423 isVisible : function(){
25424 return !this.hidden;
25429 this.fireEvent("beforeshow", this);
25431 this.hidden = false;
25432 this.el.addClass('open');
25434 Roo.get(document).on("mouseup", this.onMouseUp, this);
25436 this.fireEvent("show", this);
25443 this.fireEvent("beforehide", this);
25445 this.hidden = true;
25446 this.el.removeClass('open');
25448 Roo.get(document).un("mouseup", this.onMouseUp);
25450 this.fireEvent("hide", this);
25453 onMouseUp : function()
25467 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25470 * @class Roo.bootstrap.menu.Item
25471 * @extends Roo.bootstrap.Component
25472 * Bootstrap MenuItem class
25473 * @cfg {Boolean} submenu (true | false) default false
25474 * @cfg {String} html text of the item
25475 * @cfg {String} href the link
25476 * @cfg {Boolean} disable (true | false) default false
25477 * @cfg {Boolean} preventDefault (true | false) default true
25478 * @cfg {String} icon Font awesome icon
25479 * @cfg {String} pos Submenu align to (left | right) default right
25483 * Create a new Item
25484 * @param {Object} config The config object
25488 Roo.bootstrap.menu.Item = function(config){
25489 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25493 * Fires when the mouse is hovering over this menu
25494 * @param {Roo.bootstrap.menu.Item} this
25495 * @param {Roo.EventObject} e
25500 * Fires when the mouse exits this menu
25501 * @param {Roo.bootstrap.menu.Item} this
25502 * @param {Roo.EventObject} e
25508 * The raw click event for the entire grid.
25509 * @param {Roo.EventObject} e
25515 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25520 preventDefault: true,
25525 getAutoCreate : function()
25530 cls : 'roo-menu-item-text',
25538 cls : 'fa ' + this.icon
25547 href : this.href || '#',
25554 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25558 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25560 if(this.pos == 'left'){
25561 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25568 initEvents : function()
25570 this.el.on('mouseover', this.onMouseOver, this);
25571 this.el.on('mouseout', this.onMouseOut, this);
25573 this.el.select('a', true).first().on('click', this.onClick, this);
25577 onClick : function(e)
25579 if(this.preventDefault){
25580 e.preventDefault();
25583 this.fireEvent("click", this, e);
25586 onMouseOver : function(e)
25588 if(this.submenu && this.pos == 'left'){
25589 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25592 this.fireEvent("mouseover", this, e);
25595 onMouseOut : function(e)
25597 this.fireEvent("mouseout", this, e);
25609 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25612 * @class Roo.bootstrap.menu.Separator
25613 * @extends Roo.bootstrap.Component
25614 * Bootstrap Separator class
25617 * Create a new Separator
25618 * @param {Object} config The config object
25622 Roo.bootstrap.menu.Separator = function(config){
25623 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25626 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25628 getAutoCreate : function(){
25649 * @class Roo.bootstrap.Tooltip
25650 * Bootstrap Tooltip class
25651 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25652 * to determine which dom element triggers the tooltip.
25654 * It needs to add support for additional attributes like tooltip-position
25657 * Create a new Toolti
25658 * @param {Object} config The config object
25661 Roo.bootstrap.Tooltip = function(config){
25662 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25664 this.alignment = Roo.bootstrap.Tooltip.alignment;
25666 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25667 this.alignment = config.alignment;
25672 Roo.apply(Roo.bootstrap.Tooltip, {
25674 * @function init initialize tooltip monitoring.
25678 currentTip : false,
25679 currentRegion : false,
25685 Roo.get(document).on('mouseover', this.enter ,this);
25686 Roo.get(document).on('mouseout', this.leave, this);
25689 this.currentTip = new Roo.bootstrap.Tooltip();
25692 enter : function(ev)
25694 var dom = ev.getTarget();
25696 //Roo.log(['enter',dom]);
25697 var el = Roo.fly(dom);
25698 if (this.currentEl) {
25700 //Roo.log(this.currentEl);
25701 //Roo.log(this.currentEl.contains(dom));
25702 if (this.currentEl == el) {
25705 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25711 if (this.currentTip.el) {
25712 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25716 if(!el || el.dom == document){
25722 // you can not look for children, as if el is the body.. then everythign is the child..
25723 if (!el.attr('tooltip')) { //
25724 if (!el.select("[tooltip]").elements.length) {
25727 // is the mouse over this child...?
25728 bindEl = el.select("[tooltip]").first();
25729 var xy = ev.getXY();
25730 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25731 //Roo.log("not in region.");
25734 //Roo.log("child element over..");
25737 this.currentEl = bindEl;
25738 this.currentTip.bind(bindEl);
25739 this.currentRegion = Roo.lib.Region.getRegion(dom);
25740 this.currentTip.enter();
25743 leave : function(ev)
25745 var dom = ev.getTarget();
25746 //Roo.log(['leave',dom]);
25747 if (!this.currentEl) {
25752 if (dom != this.currentEl.dom) {
25755 var xy = ev.getXY();
25756 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25759 // only activate leave if mouse cursor is outside... bounding box..
25764 if (this.currentTip) {
25765 this.currentTip.leave();
25767 //Roo.log('clear currentEl');
25768 this.currentEl = false;
25773 'left' : ['r-l', [-2,0], 'right'],
25774 'right' : ['l-r', [2,0], 'left'],
25775 'bottom' : ['t-b', [0,2], 'top'],
25776 'top' : [ 'b-t', [0,-2], 'bottom']
25782 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25787 delay : null, // can be { show : 300 , hide: 500}
25791 hoverState : null, //???
25793 placement : 'bottom',
25797 getAutoCreate : function(){
25804 cls : 'tooltip-arrow'
25807 cls : 'tooltip-inner'
25814 bind : function(el)
25820 enter : function () {
25822 if (this.timeout != null) {
25823 clearTimeout(this.timeout);
25826 this.hoverState = 'in';
25827 //Roo.log("enter - show");
25828 if (!this.delay || !this.delay.show) {
25833 this.timeout = setTimeout(function () {
25834 if (_t.hoverState == 'in') {
25837 }, this.delay.show);
25841 clearTimeout(this.timeout);
25843 this.hoverState = 'out';
25844 if (!this.delay || !this.delay.hide) {
25850 this.timeout = setTimeout(function () {
25851 //Roo.log("leave - timeout");
25853 if (_t.hoverState == 'out') {
25855 Roo.bootstrap.Tooltip.currentEl = false;
25860 show : function (msg)
25863 this.render(document.body);
25866 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25868 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25870 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25872 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25874 var placement = typeof this.placement == 'function' ?
25875 this.placement.call(this, this.el, on_el) :
25878 var autoToken = /\s?auto?\s?/i;
25879 var autoPlace = autoToken.test(placement);
25881 placement = placement.replace(autoToken, '') || 'top';
25885 //this.el.setXY([0,0]);
25887 //this.el.dom.style.display='block';
25889 //this.el.appendTo(on_el);
25891 var p = this.getPosition();
25892 var box = this.el.getBox();
25898 var align = this.alignment[placement];
25900 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25902 if(placement == 'top' || placement == 'bottom'){
25904 placement = 'right';
25907 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25908 placement = 'left';
25911 var scroll = Roo.select('body', true).first().getScroll();
25913 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25919 this.el.alignTo(this.bindEl, align[0],align[1]);
25920 //var arrow = this.el.select('.arrow',true).first();
25921 //arrow.set(align[2],
25923 this.el.addClass(placement);
25925 this.el.addClass('in fade');
25927 this.hoverState = null;
25929 if (this.el.hasClass('fade')) {
25940 //this.el.setXY([0,0]);
25941 this.el.removeClass('in');
25957 * @class Roo.bootstrap.LocationPicker
25958 * @extends Roo.bootstrap.Component
25959 * Bootstrap LocationPicker class
25960 * @cfg {Number} latitude Position when init default 0
25961 * @cfg {Number} longitude Position when init default 0
25962 * @cfg {Number} zoom default 15
25963 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25964 * @cfg {Boolean} mapTypeControl default false
25965 * @cfg {Boolean} disableDoubleClickZoom default false
25966 * @cfg {Boolean} scrollwheel default true
25967 * @cfg {Boolean} streetViewControl default false
25968 * @cfg {Number} radius default 0
25969 * @cfg {String} locationName
25970 * @cfg {Boolean} draggable default true
25971 * @cfg {Boolean} enableAutocomplete default false
25972 * @cfg {Boolean} enableReverseGeocode default true
25973 * @cfg {String} markerTitle
25976 * Create a new LocationPicker
25977 * @param {Object} config The config object
25981 Roo.bootstrap.LocationPicker = function(config){
25983 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25988 * Fires when the picker initialized.
25989 * @param {Roo.bootstrap.LocationPicker} this
25990 * @param {Google Location} location
25994 * @event positionchanged
25995 * Fires when the picker position changed.
25996 * @param {Roo.bootstrap.LocationPicker} this
25997 * @param {Google Location} location
25999 positionchanged : true,
26002 * Fires when the map resize.
26003 * @param {Roo.bootstrap.LocationPicker} this
26008 * Fires when the map show.
26009 * @param {Roo.bootstrap.LocationPicker} this
26014 * Fires when the map hide.
26015 * @param {Roo.bootstrap.LocationPicker} this
26020 * Fires when click the map.
26021 * @param {Roo.bootstrap.LocationPicker} this
26022 * @param {Map event} e
26026 * @event mapRightClick
26027 * Fires when right click the map.
26028 * @param {Roo.bootstrap.LocationPicker} this
26029 * @param {Map event} e
26031 mapRightClick : true,
26033 * @event markerClick
26034 * Fires when click the marker.
26035 * @param {Roo.bootstrap.LocationPicker} this
26036 * @param {Map event} e
26038 markerClick : true,
26040 * @event markerRightClick
26041 * Fires when right click the marker.
26042 * @param {Roo.bootstrap.LocationPicker} this
26043 * @param {Map event} e
26045 markerRightClick : true,
26047 * @event OverlayViewDraw
26048 * Fires when OverlayView Draw
26049 * @param {Roo.bootstrap.LocationPicker} this
26051 OverlayViewDraw : true,
26053 * @event OverlayViewOnAdd
26054 * Fires when OverlayView Draw
26055 * @param {Roo.bootstrap.LocationPicker} this
26057 OverlayViewOnAdd : true,
26059 * @event OverlayViewOnRemove
26060 * Fires when OverlayView Draw
26061 * @param {Roo.bootstrap.LocationPicker} this
26063 OverlayViewOnRemove : true,
26065 * @event OverlayViewShow
26066 * Fires when OverlayView Draw
26067 * @param {Roo.bootstrap.LocationPicker} this
26068 * @param {Pixel} cpx
26070 OverlayViewShow : true,
26072 * @event OverlayViewHide
26073 * Fires when OverlayView Draw
26074 * @param {Roo.bootstrap.LocationPicker} this
26076 OverlayViewHide : true,
26078 * @event loadexception
26079 * Fires when load google lib failed.
26080 * @param {Roo.bootstrap.LocationPicker} this
26082 loadexception : true
26087 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26089 gMapContext: false,
26095 mapTypeControl: false,
26096 disableDoubleClickZoom: false,
26098 streetViewControl: false,
26102 enableAutocomplete: false,
26103 enableReverseGeocode: true,
26106 getAutoCreate: function()
26111 cls: 'roo-location-picker'
26117 initEvents: function(ct, position)
26119 if(!this.el.getWidth() || this.isApplied()){
26123 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26128 initial: function()
26130 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26131 this.fireEvent('loadexception', this);
26135 if(!this.mapTypeId){
26136 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26139 this.gMapContext = this.GMapContext();
26141 this.initOverlayView();
26143 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26147 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26148 _this.setPosition(_this.gMapContext.marker.position);
26151 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26152 _this.fireEvent('mapClick', this, event);
26156 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26157 _this.fireEvent('mapRightClick', this, event);
26161 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26162 _this.fireEvent('markerClick', this, event);
26166 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26167 _this.fireEvent('markerRightClick', this, event);
26171 this.setPosition(this.gMapContext.location);
26173 this.fireEvent('initial', this, this.gMapContext.location);
26176 initOverlayView: function()
26180 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26184 _this.fireEvent('OverlayViewDraw', _this);
26189 _this.fireEvent('OverlayViewOnAdd', _this);
26192 onRemove: function()
26194 _this.fireEvent('OverlayViewOnRemove', _this);
26197 show: function(cpx)
26199 _this.fireEvent('OverlayViewShow', _this, cpx);
26204 _this.fireEvent('OverlayViewHide', _this);
26210 fromLatLngToContainerPixel: function(event)
26212 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26215 isApplied: function()
26217 return this.getGmapContext() == false ? false : true;
26220 getGmapContext: function()
26222 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26225 GMapContext: function()
26227 var position = new google.maps.LatLng(this.latitude, this.longitude);
26229 var _map = new google.maps.Map(this.el.dom, {
26232 mapTypeId: this.mapTypeId,
26233 mapTypeControl: this.mapTypeControl,
26234 disableDoubleClickZoom: this.disableDoubleClickZoom,
26235 scrollwheel: this.scrollwheel,
26236 streetViewControl: this.streetViewControl,
26237 locationName: this.locationName,
26238 draggable: this.draggable,
26239 enableAutocomplete: this.enableAutocomplete,
26240 enableReverseGeocode: this.enableReverseGeocode
26243 var _marker = new google.maps.Marker({
26244 position: position,
26246 title: this.markerTitle,
26247 draggable: this.draggable
26254 location: position,
26255 radius: this.radius,
26256 locationName: this.locationName,
26257 addressComponents: {
26258 formatted_address: null,
26259 addressLine1: null,
26260 addressLine2: null,
26262 streetNumber: null,
26266 stateOrProvince: null
26269 domContainer: this.el.dom,
26270 geodecoder: new google.maps.Geocoder()
26274 drawCircle: function(center, radius, options)
26276 if (this.gMapContext.circle != null) {
26277 this.gMapContext.circle.setMap(null);
26281 options = Roo.apply({}, options, {
26282 strokeColor: "#0000FF",
26283 strokeOpacity: .35,
26285 fillColor: "#0000FF",
26289 options.map = this.gMapContext.map;
26290 options.radius = radius;
26291 options.center = center;
26292 this.gMapContext.circle = new google.maps.Circle(options);
26293 return this.gMapContext.circle;
26299 setPosition: function(location)
26301 this.gMapContext.location = location;
26302 this.gMapContext.marker.setPosition(location);
26303 this.gMapContext.map.panTo(location);
26304 this.drawCircle(location, this.gMapContext.radius, {});
26308 if (this.gMapContext.settings.enableReverseGeocode) {
26309 this.gMapContext.geodecoder.geocode({
26310 latLng: this.gMapContext.location
26311 }, function(results, status) {
26313 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26314 _this.gMapContext.locationName = results[0].formatted_address;
26315 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26317 _this.fireEvent('positionchanged', this, location);
26324 this.fireEvent('positionchanged', this, location);
26329 google.maps.event.trigger(this.gMapContext.map, "resize");
26331 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26333 this.fireEvent('resize', this);
26336 setPositionByLatLng: function(latitude, longitude)
26338 this.setPosition(new google.maps.LatLng(latitude, longitude));
26341 getCurrentPosition: function()
26344 latitude: this.gMapContext.location.lat(),
26345 longitude: this.gMapContext.location.lng()
26349 getAddressName: function()
26351 return this.gMapContext.locationName;
26354 getAddressComponents: function()
26356 return this.gMapContext.addressComponents;
26359 address_component_from_google_geocode: function(address_components)
26363 for (var i = 0; i < address_components.length; i++) {
26364 var component = address_components[i];
26365 if (component.types.indexOf("postal_code") >= 0) {
26366 result.postalCode = component.short_name;
26367 } else if (component.types.indexOf("street_number") >= 0) {
26368 result.streetNumber = component.short_name;
26369 } else if (component.types.indexOf("route") >= 0) {
26370 result.streetName = component.short_name;
26371 } else if (component.types.indexOf("neighborhood") >= 0) {
26372 result.city = component.short_name;
26373 } else if (component.types.indexOf("locality") >= 0) {
26374 result.city = component.short_name;
26375 } else if (component.types.indexOf("sublocality") >= 0) {
26376 result.district = component.short_name;
26377 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26378 result.stateOrProvince = component.short_name;
26379 } else if (component.types.indexOf("country") >= 0) {
26380 result.country = component.short_name;
26384 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26385 result.addressLine2 = "";
26389 setZoomLevel: function(zoom)
26391 this.gMapContext.map.setZoom(zoom);
26404 this.fireEvent('show', this);
26415 this.fireEvent('hide', this);
26420 Roo.apply(Roo.bootstrap.LocationPicker, {
26422 OverlayView : function(map, options)
26424 options = options || {};
26438 * @class Roo.bootstrap.Alert
26439 * @extends Roo.bootstrap.Component
26440 * Bootstrap Alert class
26441 * @cfg {String} title The title of alert
26442 * @cfg {String} html The content of alert
26443 * @cfg {String} weight ( success | info | warning | danger )
26444 * @cfg {String} faicon font-awesomeicon
26447 * Create a new alert
26448 * @param {Object} config The config object
26452 Roo.bootstrap.Alert = function(config){
26453 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26457 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26464 getAutoCreate : function()
26473 cls : 'roo-alert-icon'
26478 cls : 'roo-alert-title',
26483 cls : 'roo-alert-text',
26490 cfg.cn[0].cls += ' fa ' + this.faicon;
26494 cfg.cls += ' alert-' + this.weight;
26500 initEvents: function()
26502 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26505 setTitle : function(str)
26507 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26510 setText : function(str)
26512 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26515 setWeight : function(weight)
26518 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26521 this.weight = weight;
26523 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26526 setIcon : function(icon)
26529 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26532 this.faicon = icon;
26534 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26555 * @class Roo.bootstrap.UploadCropbox
26556 * @extends Roo.bootstrap.Component
26557 * Bootstrap UploadCropbox class
26558 * @cfg {String} emptyText show when image has been loaded
26559 * @cfg {String} rotateNotify show when image too small to rotate
26560 * @cfg {Number} errorTimeout default 3000
26561 * @cfg {Number} minWidth default 300
26562 * @cfg {Number} minHeight default 300
26563 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26564 * @cfg {Boolean} isDocument (true|false) default false
26565 * @cfg {String} url action url
26566 * @cfg {String} paramName default 'imageUpload'
26567 * @cfg {String} method default POST
26568 * @cfg {Boolean} loadMask (true|false) default true
26569 * @cfg {Boolean} loadingText default 'Loading...'
26572 * Create a new UploadCropbox
26573 * @param {Object} config The config object
26576 Roo.bootstrap.UploadCropbox = function(config){
26577 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26581 * @event beforeselectfile
26582 * Fire before select file
26583 * @param {Roo.bootstrap.UploadCropbox} this
26585 "beforeselectfile" : true,
26588 * Fire after initEvent
26589 * @param {Roo.bootstrap.UploadCropbox} this
26594 * Fire after initEvent
26595 * @param {Roo.bootstrap.UploadCropbox} this
26596 * @param {String} data
26601 * Fire when preparing the file data
26602 * @param {Roo.bootstrap.UploadCropbox} this
26603 * @param {Object} file
26608 * Fire when get exception
26609 * @param {Roo.bootstrap.UploadCropbox} this
26610 * @param {XMLHttpRequest} xhr
26612 "exception" : true,
26614 * @event beforeloadcanvas
26615 * Fire before load the canvas
26616 * @param {Roo.bootstrap.UploadCropbox} this
26617 * @param {String} src
26619 "beforeloadcanvas" : true,
26622 * Fire when trash image
26623 * @param {Roo.bootstrap.UploadCropbox} this
26628 * Fire when download the image
26629 * @param {Roo.bootstrap.UploadCropbox} this
26633 * @event footerbuttonclick
26634 * Fire when footerbuttonclick
26635 * @param {Roo.bootstrap.UploadCropbox} this
26636 * @param {String} type
26638 "footerbuttonclick" : true,
26642 * @param {Roo.bootstrap.UploadCropbox} this
26647 * Fire when rotate the image
26648 * @param {Roo.bootstrap.UploadCropbox} this
26649 * @param {String} pos
26654 * Fire when inspect the file
26655 * @param {Roo.bootstrap.UploadCropbox} this
26656 * @param {Object} file
26661 * Fire when xhr upload the file
26662 * @param {Roo.bootstrap.UploadCropbox} this
26663 * @param {Object} data
26668 * Fire when arrange the file data
26669 * @param {Roo.bootstrap.UploadCropbox} this
26670 * @param {Object} formData
26675 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26678 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26680 emptyText : 'Click to upload image',
26681 rotateNotify : 'Image is too small to rotate',
26682 errorTimeout : 3000,
26696 cropType : 'image/jpeg',
26698 canvasLoaded : false,
26699 isDocument : false,
26701 paramName : 'imageUpload',
26703 loadingText : 'Loading...',
26706 getAutoCreate : function()
26710 cls : 'roo-upload-cropbox',
26714 cls : 'roo-upload-cropbox-selector',
26719 cls : 'roo-upload-cropbox-body',
26720 style : 'cursor:pointer',
26724 cls : 'roo-upload-cropbox-preview'
26728 cls : 'roo-upload-cropbox-thumb'
26732 cls : 'roo-upload-cropbox-empty-notify',
26733 html : this.emptyText
26737 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26738 html : this.rotateNotify
26744 cls : 'roo-upload-cropbox-footer',
26747 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26757 onRender : function(ct, position)
26759 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26761 if (this.buttons.length) {
26763 Roo.each(this.buttons, function(bb) {
26765 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26767 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26773 this.maskEl = this.el;
26777 initEvents : function()
26779 this.urlAPI = (window.createObjectURL && window) ||
26780 (window.URL && URL.revokeObjectURL && URL) ||
26781 (window.webkitURL && webkitURL);
26783 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26784 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26786 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26787 this.selectorEl.hide();
26789 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26790 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26792 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26793 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26794 this.thumbEl.hide();
26796 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26797 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26799 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26800 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26801 this.errorEl.hide();
26803 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26804 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26805 this.footerEl.hide();
26807 this.setThumbBoxSize();
26813 this.fireEvent('initial', this);
26820 window.addEventListener("resize", function() { _this.resize(); } );
26822 this.bodyEl.on('click', this.beforeSelectFile, this);
26825 this.bodyEl.on('touchstart', this.onTouchStart, this);
26826 this.bodyEl.on('touchmove', this.onTouchMove, this);
26827 this.bodyEl.on('touchend', this.onTouchEnd, this);
26831 this.bodyEl.on('mousedown', this.onMouseDown, this);
26832 this.bodyEl.on('mousemove', this.onMouseMove, this);
26833 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26834 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26835 Roo.get(document).on('mouseup', this.onMouseUp, this);
26838 this.selectorEl.on('change', this.onFileSelected, this);
26844 this.baseScale = 1;
26846 this.baseRotate = 1;
26847 this.dragable = false;
26848 this.pinching = false;
26851 this.cropData = false;
26852 this.notifyEl.dom.innerHTML = this.emptyText;
26854 this.selectorEl.dom.value = '';
26858 resize : function()
26860 if(this.fireEvent('resize', this) != false){
26861 this.setThumbBoxPosition();
26862 this.setCanvasPosition();
26866 onFooterButtonClick : function(e, el, o, type)
26869 case 'rotate-left' :
26870 this.onRotateLeft(e);
26872 case 'rotate-right' :
26873 this.onRotateRight(e);
26876 this.beforeSelectFile(e);
26891 this.fireEvent('footerbuttonclick', this, type);
26894 beforeSelectFile : function(e)
26896 e.preventDefault();
26898 if(this.fireEvent('beforeselectfile', this) != false){
26899 this.selectorEl.dom.click();
26903 onFileSelected : function(e)
26905 e.preventDefault();
26907 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26911 var file = this.selectorEl.dom.files[0];
26913 if(this.fireEvent('inspect', this, file) != false){
26914 this.prepare(file);
26919 trash : function(e)
26921 this.fireEvent('trash', this);
26924 download : function(e)
26926 this.fireEvent('download', this);
26929 loadCanvas : function(src)
26931 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26935 this.imageEl = document.createElement('img');
26939 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26941 this.imageEl.src = src;
26945 onLoadCanvas : function()
26947 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26948 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26950 this.bodyEl.un('click', this.beforeSelectFile, this);
26952 this.notifyEl.hide();
26953 this.thumbEl.show();
26954 this.footerEl.show();
26956 this.baseRotateLevel();
26958 if(this.isDocument){
26959 this.setThumbBoxSize();
26962 this.setThumbBoxPosition();
26964 this.baseScaleLevel();
26970 this.canvasLoaded = true;
26973 this.maskEl.unmask();
26978 setCanvasPosition : function()
26980 if(!this.canvasEl){
26984 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26985 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26987 this.previewEl.setLeft(pw);
26988 this.previewEl.setTop(ph);
26992 onMouseDown : function(e)
26996 this.dragable = true;
26997 this.pinching = false;
26999 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27000 this.dragable = false;
27004 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27005 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27009 onMouseMove : function(e)
27013 if(!this.canvasLoaded){
27017 if (!this.dragable){
27021 var minX = Math.ceil(this.thumbEl.getLeft(true));
27022 var minY = Math.ceil(this.thumbEl.getTop(true));
27024 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27025 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27027 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27028 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27030 x = x - this.mouseX;
27031 y = y - this.mouseY;
27033 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27034 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27036 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27037 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27039 this.previewEl.setLeft(bgX);
27040 this.previewEl.setTop(bgY);
27042 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27043 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27046 onMouseUp : function(e)
27050 this.dragable = false;
27053 onMouseWheel : function(e)
27057 this.startScale = this.scale;
27059 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27061 if(!this.zoomable()){
27062 this.scale = this.startScale;
27071 zoomable : function()
27073 var minScale = this.thumbEl.getWidth() / this.minWidth;
27075 if(this.minWidth < this.minHeight){
27076 minScale = this.thumbEl.getHeight() / this.minHeight;
27079 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27080 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27084 (this.rotate == 0 || this.rotate == 180) &&
27086 width > this.imageEl.OriginWidth ||
27087 height > this.imageEl.OriginHeight ||
27088 (width < this.minWidth && height < this.minHeight)
27096 (this.rotate == 90 || this.rotate == 270) &&
27098 width > this.imageEl.OriginWidth ||
27099 height > this.imageEl.OriginHeight ||
27100 (width < this.minHeight && height < this.minWidth)
27107 !this.isDocument &&
27108 (this.rotate == 0 || this.rotate == 180) &&
27110 width < this.minWidth ||
27111 width > this.imageEl.OriginWidth ||
27112 height < this.minHeight ||
27113 height > this.imageEl.OriginHeight
27120 !this.isDocument &&
27121 (this.rotate == 90 || this.rotate == 270) &&
27123 width < this.minHeight ||
27124 width > this.imageEl.OriginWidth ||
27125 height < this.minWidth ||
27126 height > this.imageEl.OriginHeight
27136 onRotateLeft : function(e)
27138 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27140 var minScale = this.thumbEl.getWidth() / this.minWidth;
27142 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27143 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27145 this.startScale = this.scale;
27147 while (this.getScaleLevel() < minScale){
27149 this.scale = this.scale + 1;
27151 if(!this.zoomable()){
27156 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27157 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27162 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27169 this.scale = this.startScale;
27171 this.onRotateFail();
27176 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27178 if(this.isDocument){
27179 this.setThumbBoxSize();
27180 this.setThumbBoxPosition();
27181 this.setCanvasPosition();
27186 this.fireEvent('rotate', this, 'left');
27190 onRotateRight : function(e)
27192 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27194 var minScale = this.thumbEl.getWidth() / this.minWidth;
27196 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27197 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27199 this.startScale = this.scale;
27201 while (this.getScaleLevel() < minScale){
27203 this.scale = this.scale + 1;
27205 if(!this.zoomable()){
27210 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27211 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27216 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27223 this.scale = this.startScale;
27225 this.onRotateFail();
27230 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27232 if(this.isDocument){
27233 this.setThumbBoxSize();
27234 this.setThumbBoxPosition();
27235 this.setCanvasPosition();
27240 this.fireEvent('rotate', this, 'right');
27243 onRotateFail : function()
27245 this.errorEl.show(true);
27249 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27254 this.previewEl.dom.innerHTML = '';
27256 var canvasEl = document.createElement("canvas");
27258 var contextEl = canvasEl.getContext("2d");
27260 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27261 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27262 var center = this.imageEl.OriginWidth / 2;
27264 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27265 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27266 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27267 center = this.imageEl.OriginHeight / 2;
27270 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27272 contextEl.translate(center, center);
27273 contextEl.rotate(this.rotate * Math.PI / 180);
27275 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27277 this.canvasEl = document.createElement("canvas");
27279 this.contextEl = this.canvasEl.getContext("2d");
27281 switch (this.rotate) {
27284 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27285 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27287 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27292 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27293 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27295 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27296 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27300 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27305 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27306 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27308 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27309 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27313 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);
27318 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27319 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27321 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27322 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27326 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);
27333 this.previewEl.appendChild(this.canvasEl);
27335 this.setCanvasPosition();
27340 if(!this.canvasLoaded){
27344 var imageCanvas = document.createElement("canvas");
27346 var imageContext = imageCanvas.getContext("2d");
27348 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27349 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27351 var center = imageCanvas.width / 2;
27353 imageContext.translate(center, center);
27355 imageContext.rotate(this.rotate * Math.PI / 180);
27357 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27359 var canvas = document.createElement("canvas");
27361 var context = canvas.getContext("2d");
27363 canvas.width = this.minWidth;
27364 canvas.height = this.minHeight;
27366 switch (this.rotate) {
27369 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27370 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27372 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27373 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27375 var targetWidth = this.minWidth - 2 * x;
27376 var targetHeight = this.minHeight - 2 * y;
27380 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27381 scale = targetWidth / width;
27384 if(x > 0 && y == 0){
27385 scale = targetHeight / height;
27388 if(x > 0 && y > 0){
27389 scale = targetWidth / width;
27391 if(width < height){
27392 scale = targetHeight / height;
27396 context.scale(scale, scale);
27398 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27399 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27401 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27402 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27404 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27409 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27410 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27412 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27413 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27415 var targetWidth = this.minWidth - 2 * x;
27416 var targetHeight = this.minHeight - 2 * y;
27420 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27421 scale = targetWidth / width;
27424 if(x > 0 && y == 0){
27425 scale = targetHeight / height;
27428 if(x > 0 && y > 0){
27429 scale = targetWidth / width;
27431 if(width < height){
27432 scale = targetHeight / height;
27436 context.scale(scale, scale);
27438 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27439 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27441 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27442 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27444 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27446 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27451 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27452 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27454 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27455 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27457 var targetWidth = this.minWidth - 2 * x;
27458 var targetHeight = this.minHeight - 2 * y;
27462 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27463 scale = targetWidth / width;
27466 if(x > 0 && y == 0){
27467 scale = targetHeight / height;
27470 if(x > 0 && y > 0){
27471 scale = targetWidth / width;
27473 if(width < height){
27474 scale = targetHeight / height;
27478 context.scale(scale, scale);
27480 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27481 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27483 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27484 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27486 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27487 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27489 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27494 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27495 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27497 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27498 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27500 var targetWidth = this.minWidth - 2 * x;
27501 var targetHeight = this.minHeight - 2 * y;
27505 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27506 scale = targetWidth / width;
27509 if(x > 0 && y == 0){
27510 scale = targetHeight / height;
27513 if(x > 0 && y > 0){
27514 scale = targetWidth / width;
27516 if(width < height){
27517 scale = targetHeight / height;
27521 context.scale(scale, scale);
27523 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27524 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27526 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27527 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27529 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27531 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27538 this.cropData = canvas.toDataURL(this.cropType);
27540 if(this.fireEvent('crop', this, this.cropData) !== false){
27541 this.process(this.file, this.cropData);
27548 setThumbBoxSize : function()
27552 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27553 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27554 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27556 this.minWidth = width;
27557 this.minHeight = height;
27559 if(this.rotate == 90 || this.rotate == 270){
27560 this.minWidth = height;
27561 this.minHeight = width;
27566 width = Math.ceil(this.minWidth * height / this.minHeight);
27568 if(this.minWidth > this.minHeight){
27570 height = Math.ceil(this.minHeight * width / this.minWidth);
27573 this.thumbEl.setStyle({
27574 width : width + 'px',
27575 height : height + 'px'
27582 setThumbBoxPosition : function()
27584 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27585 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27587 this.thumbEl.setLeft(x);
27588 this.thumbEl.setTop(y);
27592 baseRotateLevel : function()
27594 this.baseRotate = 1;
27597 typeof(this.exif) != 'undefined' &&
27598 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27599 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27601 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27604 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27608 baseScaleLevel : function()
27612 if(this.isDocument){
27614 if(this.baseRotate == 6 || this.baseRotate == 8){
27616 height = this.thumbEl.getHeight();
27617 this.baseScale = height / this.imageEl.OriginWidth;
27619 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27620 width = this.thumbEl.getWidth();
27621 this.baseScale = width / this.imageEl.OriginHeight;
27627 height = this.thumbEl.getHeight();
27628 this.baseScale = height / this.imageEl.OriginHeight;
27630 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27631 width = this.thumbEl.getWidth();
27632 this.baseScale = width / this.imageEl.OriginWidth;
27638 if(this.baseRotate == 6 || this.baseRotate == 8){
27640 width = this.thumbEl.getHeight();
27641 this.baseScale = width / this.imageEl.OriginHeight;
27643 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27644 height = this.thumbEl.getWidth();
27645 this.baseScale = height / this.imageEl.OriginHeight;
27648 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27649 height = this.thumbEl.getWidth();
27650 this.baseScale = height / this.imageEl.OriginHeight;
27652 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27653 width = this.thumbEl.getHeight();
27654 this.baseScale = width / this.imageEl.OriginWidth;
27661 width = this.thumbEl.getWidth();
27662 this.baseScale = width / this.imageEl.OriginWidth;
27664 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27665 height = this.thumbEl.getHeight();
27666 this.baseScale = height / this.imageEl.OriginHeight;
27669 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27671 height = this.thumbEl.getHeight();
27672 this.baseScale = height / this.imageEl.OriginHeight;
27674 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27675 width = this.thumbEl.getWidth();
27676 this.baseScale = width / this.imageEl.OriginWidth;
27684 getScaleLevel : function()
27686 return this.baseScale * Math.pow(1.1, this.scale);
27689 onTouchStart : function(e)
27691 if(!this.canvasLoaded){
27692 this.beforeSelectFile(e);
27696 var touches = e.browserEvent.touches;
27702 if(touches.length == 1){
27703 this.onMouseDown(e);
27707 if(touches.length != 2){
27713 for(var i = 0, finger; finger = touches[i]; i++){
27714 coords.push(finger.pageX, finger.pageY);
27717 var x = Math.pow(coords[0] - coords[2], 2);
27718 var y = Math.pow(coords[1] - coords[3], 2);
27720 this.startDistance = Math.sqrt(x + y);
27722 this.startScale = this.scale;
27724 this.pinching = true;
27725 this.dragable = false;
27729 onTouchMove : function(e)
27731 if(!this.pinching && !this.dragable){
27735 var touches = e.browserEvent.touches;
27742 this.onMouseMove(e);
27748 for(var i = 0, finger; finger = touches[i]; i++){
27749 coords.push(finger.pageX, finger.pageY);
27752 var x = Math.pow(coords[0] - coords[2], 2);
27753 var y = Math.pow(coords[1] - coords[3], 2);
27755 this.endDistance = Math.sqrt(x + y);
27757 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27759 if(!this.zoomable()){
27760 this.scale = this.startScale;
27768 onTouchEnd : function(e)
27770 this.pinching = false;
27771 this.dragable = false;
27775 process : function(file, crop)
27778 this.maskEl.mask(this.loadingText);
27781 this.xhr = new XMLHttpRequest();
27783 file.xhr = this.xhr;
27785 this.xhr.open(this.method, this.url, true);
27788 "Accept": "application/json",
27789 "Cache-Control": "no-cache",
27790 "X-Requested-With": "XMLHttpRequest"
27793 for (var headerName in headers) {
27794 var headerValue = headers[headerName];
27796 this.xhr.setRequestHeader(headerName, headerValue);
27802 this.xhr.onload = function()
27804 _this.xhrOnLoad(_this.xhr);
27807 this.xhr.onerror = function()
27809 _this.xhrOnError(_this.xhr);
27812 var formData = new FormData();
27814 formData.append('returnHTML', 'NO');
27817 formData.append('crop', crop);
27820 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27821 formData.append(this.paramName, file, file.name);
27824 if(typeof(file.filename) != 'undefined'){
27825 formData.append('filename', file.filename);
27828 if(typeof(file.mimetype) != 'undefined'){
27829 formData.append('mimetype', file.mimetype);
27832 if(this.fireEvent('arrange', this, formData) != false){
27833 this.xhr.send(formData);
27837 xhrOnLoad : function(xhr)
27840 this.maskEl.unmask();
27843 if (xhr.readyState !== 4) {
27844 this.fireEvent('exception', this, xhr);
27848 var response = Roo.decode(xhr.responseText);
27850 if(!response.success){
27851 this.fireEvent('exception', this, xhr);
27855 var response = Roo.decode(xhr.responseText);
27857 this.fireEvent('upload', this, response);
27861 xhrOnError : function()
27864 this.maskEl.unmask();
27867 Roo.log('xhr on error');
27869 var response = Roo.decode(xhr.responseText);
27875 prepare : function(file)
27878 this.maskEl.mask(this.loadingText);
27884 if(typeof(file) === 'string'){
27885 this.loadCanvas(file);
27889 if(!file || !this.urlAPI){
27894 this.cropType = file.type;
27898 if(this.fireEvent('prepare', this, this.file) != false){
27900 var reader = new FileReader();
27902 reader.onload = function (e) {
27903 if (e.target.error) {
27904 Roo.log(e.target.error);
27908 var buffer = e.target.result,
27909 dataView = new DataView(buffer),
27911 maxOffset = dataView.byteLength - 4,
27915 if (dataView.getUint16(0) === 0xffd8) {
27916 while (offset < maxOffset) {
27917 markerBytes = dataView.getUint16(offset);
27919 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27920 markerLength = dataView.getUint16(offset + 2) + 2;
27921 if (offset + markerLength > dataView.byteLength) {
27922 Roo.log('Invalid meta data: Invalid segment size.');
27926 if(markerBytes == 0xffe1){
27927 _this.parseExifData(
27934 offset += markerLength;
27944 var url = _this.urlAPI.createObjectURL(_this.file);
27946 _this.loadCanvas(url);
27951 reader.readAsArrayBuffer(this.file);
27957 parseExifData : function(dataView, offset, length)
27959 var tiffOffset = offset + 10,
27963 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27964 // No Exif data, might be XMP data instead
27968 // Check for the ASCII code for "Exif" (0x45786966):
27969 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27970 // No Exif data, might be XMP data instead
27973 if (tiffOffset + 8 > dataView.byteLength) {
27974 Roo.log('Invalid Exif data: Invalid segment size.');
27977 // Check for the two null bytes:
27978 if (dataView.getUint16(offset + 8) !== 0x0000) {
27979 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27982 // Check the byte alignment:
27983 switch (dataView.getUint16(tiffOffset)) {
27985 littleEndian = true;
27988 littleEndian = false;
27991 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27994 // Check for the TIFF tag marker (0x002A):
27995 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27996 Roo.log('Invalid Exif data: Missing TIFF marker.');
27999 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28000 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28002 this.parseExifTags(
28005 tiffOffset + dirOffset,
28010 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28015 if (dirOffset + 6 > dataView.byteLength) {
28016 Roo.log('Invalid Exif data: Invalid directory offset.');
28019 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28020 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28021 if (dirEndOffset + 4 > dataView.byteLength) {
28022 Roo.log('Invalid Exif data: Invalid directory size.');
28025 for (i = 0; i < tagsNumber; i += 1) {
28029 dirOffset + 2 + 12 * i, // tag offset
28033 // Return the offset to the next directory:
28034 return dataView.getUint32(dirEndOffset, littleEndian);
28037 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28039 var tag = dataView.getUint16(offset, littleEndian);
28041 this.exif[tag] = this.getExifValue(
28045 dataView.getUint16(offset + 2, littleEndian), // tag type
28046 dataView.getUint32(offset + 4, littleEndian), // tag length
28051 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28053 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28062 Roo.log('Invalid Exif data: Invalid tag type.');
28066 tagSize = tagType.size * length;
28067 // Determine if the value is contained in the dataOffset bytes,
28068 // or if the value at the dataOffset is a pointer to the actual data:
28069 dataOffset = tagSize > 4 ?
28070 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28071 if (dataOffset + tagSize > dataView.byteLength) {
28072 Roo.log('Invalid Exif data: Invalid data offset.');
28075 if (length === 1) {
28076 return tagType.getValue(dataView, dataOffset, littleEndian);
28079 for (i = 0; i < length; i += 1) {
28080 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28083 if (tagType.ascii) {
28085 // Concatenate the chars:
28086 for (i = 0; i < values.length; i += 1) {
28088 // Ignore the terminating NULL byte(s):
28089 if (c === '\u0000') {
28101 Roo.apply(Roo.bootstrap.UploadCropbox, {
28103 'Orientation': 0x0112
28107 1: 0, //'top-left',
28109 3: 180, //'bottom-right',
28110 // 4: 'bottom-left',
28112 6: 90, //'right-top',
28113 // 7: 'right-bottom',
28114 8: 270 //'left-bottom'
28118 // byte, 8-bit unsigned int:
28120 getValue: function (dataView, dataOffset) {
28121 return dataView.getUint8(dataOffset);
28125 // ascii, 8-bit byte:
28127 getValue: function (dataView, dataOffset) {
28128 return String.fromCharCode(dataView.getUint8(dataOffset));
28133 // short, 16 bit int:
28135 getValue: function (dataView, dataOffset, littleEndian) {
28136 return dataView.getUint16(dataOffset, littleEndian);
28140 // long, 32 bit int:
28142 getValue: function (dataView, dataOffset, littleEndian) {
28143 return dataView.getUint32(dataOffset, littleEndian);
28147 // rational = two long values, first is numerator, second is denominator:
28149 getValue: function (dataView, dataOffset, littleEndian) {
28150 return dataView.getUint32(dataOffset, littleEndian) /
28151 dataView.getUint32(dataOffset + 4, littleEndian);
28155 // slong, 32 bit signed int:
28157 getValue: function (dataView, dataOffset, littleEndian) {
28158 return dataView.getInt32(dataOffset, littleEndian);
28162 // srational, two slongs, first is numerator, second is denominator:
28164 getValue: function (dataView, dataOffset, littleEndian) {
28165 return dataView.getInt32(dataOffset, littleEndian) /
28166 dataView.getInt32(dataOffset + 4, littleEndian);
28176 cls : 'btn-group roo-upload-cropbox-rotate-left',
28177 action : 'rotate-left',
28181 cls : 'btn btn-default',
28182 html : '<i class="fa fa-undo"></i>'
28188 cls : 'btn-group roo-upload-cropbox-picture',
28189 action : 'picture',
28193 cls : 'btn btn-default',
28194 html : '<i class="fa fa-picture-o"></i>'
28200 cls : 'btn-group roo-upload-cropbox-rotate-right',
28201 action : 'rotate-right',
28205 cls : 'btn btn-default',
28206 html : '<i class="fa fa-repeat"></i>'
28214 cls : 'btn-group roo-upload-cropbox-rotate-left',
28215 action : 'rotate-left',
28219 cls : 'btn btn-default',
28220 html : '<i class="fa fa-undo"></i>'
28226 cls : 'btn-group roo-upload-cropbox-download',
28227 action : 'download',
28231 cls : 'btn btn-default',
28232 html : '<i class="fa fa-download"></i>'
28238 cls : 'btn-group roo-upload-cropbox-crop',
28243 cls : 'btn btn-default',
28244 html : '<i class="fa fa-crop"></i>'
28250 cls : 'btn-group roo-upload-cropbox-trash',
28255 cls : 'btn btn-default',
28256 html : '<i class="fa fa-trash"></i>'
28262 cls : 'btn-group roo-upload-cropbox-rotate-right',
28263 action : 'rotate-right',
28267 cls : 'btn btn-default',
28268 html : '<i class="fa fa-repeat"></i>'
28276 cls : 'btn-group roo-upload-cropbox-rotate-left',
28277 action : 'rotate-left',
28281 cls : 'btn btn-default',
28282 html : '<i class="fa fa-undo"></i>'
28288 cls : 'btn-group roo-upload-cropbox-rotate-right',
28289 action : 'rotate-right',
28293 cls : 'btn btn-default',
28294 html : '<i class="fa fa-repeat"></i>'
28307 * @class Roo.bootstrap.DocumentManager
28308 * @extends Roo.bootstrap.Component
28309 * Bootstrap DocumentManager class
28310 * @cfg {String} paramName default 'imageUpload'
28311 * @cfg {String} toolTipName default 'filename'
28312 * @cfg {String} method default POST
28313 * @cfg {String} url action url
28314 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28315 * @cfg {Boolean} multiple multiple upload default true
28316 * @cfg {Number} thumbSize default 300
28317 * @cfg {String} fieldLabel
28318 * @cfg {Number} labelWidth default 4
28319 * @cfg {String} labelAlign (left|top) default left
28320 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28321 * @cfg {Number} labellg set the width of label (1-12)
28322 * @cfg {Number} labelmd set the width of label (1-12)
28323 * @cfg {Number} labelsm set the width of label (1-12)
28324 * @cfg {Number} labelxs set the width of label (1-12)
28327 * Create a new DocumentManager
28328 * @param {Object} config The config object
28331 Roo.bootstrap.DocumentManager = function(config){
28332 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28335 this.delegates = [];
28340 * Fire when initial the DocumentManager
28341 * @param {Roo.bootstrap.DocumentManager} this
28346 * inspect selected file
28347 * @param {Roo.bootstrap.DocumentManager} this
28348 * @param {File} file
28353 * Fire when xhr load exception
28354 * @param {Roo.bootstrap.DocumentManager} this
28355 * @param {XMLHttpRequest} xhr
28357 "exception" : true,
28359 * @event afterupload
28360 * Fire when xhr load exception
28361 * @param {Roo.bootstrap.DocumentManager} this
28362 * @param {XMLHttpRequest} xhr
28364 "afterupload" : true,
28367 * prepare the form data
28368 * @param {Roo.bootstrap.DocumentManager} this
28369 * @param {Object} formData
28374 * Fire when remove the file
28375 * @param {Roo.bootstrap.DocumentManager} this
28376 * @param {Object} file
28381 * Fire after refresh the file
28382 * @param {Roo.bootstrap.DocumentManager} this
28387 * Fire after click the image
28388 * @param {Roo.bootstrap.DocumentManager} this
28389 * @param {Object} file
28394 * Fire when upload a image and editable set to true
28395 * @param {Roo.bootstrap.DocumentManager} this
28396 * @param {Object} file
28400 * @event beforeselectfile
28401 * Fire before select file
28402 * @param {Roo.bootstrap.DocumentManager} this
28404 "beforeselectfile" : true,
28407 * Fire before process file
28408 * @param {Roo.bootstrap.DocumentManager} this
28409 * @param {Object} file
28416 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28425 paramName : 'imageUpload',
28426 toolTipName : 'filename',
28429 labelAlign : 'left',
28439 getAutoCreate : function()
28441 var managerWidget = {
28443 cls : 'roo-document-manager',
28447 cls : 'roo-document-manager-selector',
28452 cls : 'roo-document-manager-uploader',
28456 cls : 'roo-document-manager-upload-btn',
28457 html : '<i class="fa fa-plus"></i>'
28468 cls : 'column col-md-12',
28473 if(this.fieldLabel.length){
28478 cls : 'column col-md-12',
28479 html : this.fieldLabel
28483 cls : 'column col-md-12',
28488 if(this.labelAlign == 'left'){
28493 html : this.fieldLabel
28502 if(this.labelWidth > 12){
28503 content[0].style = "width: " + this.labelWidth + 'px';
28506 if(this.labelWidth < 13 && this.labelmd == 0){
28507 this.labelmd = this.labelWidth;
28510 if(this.labellg > 0){
28511 content[0].cls += ' col-lg-' + this.labellg;
28512 content[1].cls += ' col-lg-' + (12 - this.labellg);
28515 if(this.labelmd > 0){
28516 content[0].cls += ' col-md-' + this.labelmd;
28517 content[1].cls += ' col-md-' + (12 - this.labelmd);
28520 if(this.labelsm > 0){
28521 content[0].cls += ' col-sm-' + this.labelsm;
28522 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28525 if(this.labelxs > 0){
28526 content[0].cls += ' col-xs-' + this.labelxs;
28527 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28535 cls : 'row clearfix',
28543 initEvents : function()
28545 this.managerEl = this.el.select('.roo-document-manager', true).first();
28546 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28548 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28549 this.selectorEl.hide();
28552 this.selectorEl.attr('multiple', 'multiple');
28555 this.selectorEl.on('change', this.onFileSelected, this);
28557 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28558 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28560 this.uploader.on('click', this.onUploaderClick, this);
28562 this.renderProgressDialog();
28566 window.addEventListener("resize", function() { _this.refresh(); } );
28568 this.fireEvent('initial', this);
28571 renderProgressDialog : function()
28575 this.progressDialog = new Roo.bootstrap.Modal({
28576 cls : 'roo-document-manager-progress-dialog',
28577 allow_close : false,
28587 btnclick : function() {
28588 _this.uploadCancel();
28594 this.progressDialog.render(Roo.get(document.body));
28596 this.progress = new Roo.bootstrap.Progress({
28597 cls : 'roo-document-manager-progress',
28602 this.progress.render(this.progressDialog.getChildContainer());
28604 this.progressBar = new Roo.bootstrap.ProgressBar({
28605 cls : 'roo-document-manager-progress-bar',
28608 aria_valuemax : 12,
28612 this.progressBar.render(this.progress.getChildContainer());
28615 onUploaderClick : function(e)
28617 e.preventDefault();
28619 if(this.fireEvent('beforeselectfile', this) != false){
28620 this.selectorEl.dom.click();
28625 onFileSelected : function(e)
28627 e.preventDefault();
28629 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28633 Roo.each(this.selectorEl.dom.files, function(file){
28634 if(this.fireEvent('inspect', this, file) != false){
28635 this.files.push(file);
28645 this.selectorEl.dom.value = '';
28647 if(!this.files.length){
28651 if(this.boxes > 0 && this.files.length > this.boxes){
28652 this.files = this.files.slice(0, this.boxes);
28655 this.uploader.show();
28657 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28658 this.uploader.hide();
28667 Roo.each(this.files, function(file){
28669 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28670 var f = this.renderPreview(file);
28675 if(file.type.indexOf('image') != -1){
28676 this.delegates.push(
28678 _this.process(file);
28679 }).createDelegate(this)
28687 _this.process(file);
28688 }).createDelegate(this)
28693 this.files = files;
28695 this.delegates = this.delegates.concat(docs);
28697 if(!this.delegates.length){
28702 this.progressBar.aria_valuemax = this.delegates.length;
28709 arrange : function()
28711 if(!this.delegates.length){
28712 this.progressDialog.hide();
28717 var delegate = this.delegates.shift();
28719 this.progressDialog.show();
28721 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28723 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28728 refresh : function()
28730 this.uploader.show();
28732 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28733 this.uploader.hide();
28736 Roo.isTouch ? this.closable(false) : this.closable(true);
28738 this.fireEvent('refresh', this);
28741 onRemove : function(e, el, o)
28743 e.preventDefault();
28745 this.fireEvent('remove', this, o);
28749 remove : function(o)
28753 Roo.each(this.files, function(file){
28754 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28763 this.files = files;
28770 Roo.each(this.files, function(file){
28775 file.target.remove();
28784 onClick : function(e, el, o)
28786 e.preventDefault();
28788 this.fireEvent('click', this, o);
28792 closable : function(closable)
28794 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28796 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28808 xhrOnLoad : function(xhr)
28810 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28814 if (xhr.readyState !== 4) {
28816 this.fireEvent('exception', this, xhr);
28820 var response = Roo.decode(xhr.responseText);
28822 if(!response.success){
28824 this.fireEvent('exception', this, xhr);
28828 var file = this.renderPreview(response.data);
28830 this.files.push(file);
28834 this.fireEvent('afterupload', this, xhr);
28838 xhrOnError : function(xhr)
28840 Roo.log('xhr on error');
28842 var response = Roo.decode(xhr.responseText);
28849 process : function(file)
28851 if(this.fireEvent('process', this, file) !== false){
28852 if(this.editable && file.type.indexOf('image') != -1){
28853 this.fireEvent('edit', this, file);
28857 this.uploadStart(file, false);
28864 uploadStart : function(file, crop)
28866 this.xhr = new XMLHttpRequest();
28868 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28873 file.xhr = this.xhr;
28875 this.managerEl.createChild({
28877 cls : 'roo-document-manager-loading',
28881 tooltip : file.name,
28882 cls : 'roo-document-manager-thumb',
28883 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28889 this.xhr.open(this.method, this.url, true);
28892 "Accept": "application/json",
28893 "Cache-Control": "no-cache",
28894 "X-Requested-With": "XMLHttpRequest"
28897 for (var headerName in headers) {
28898 var headerValue = headers[headerName];
28900 this.xhr.setRequestHeader(headerName, headerValue);
28906 this.xhr.onload = function()
28908 _this.xhrOnLoad(_this.xhr);
28911 this.xhr.onerror = function()
28913 _this.xhrOnError(_this.xhr);
28916 var formData = new FormData();
28918 formData.append('returnHTML', 'NO');
28921 formData.append('crop', crop);
28924 formData.append(this.paramName, file, file.name);
28931 if(this.fireEvent('prepare', this, formData, options) != false){
28933 if(options.manually){
28937 this.xhr.send(formData);
28941 this.uploadCancel();
28944 uploadCancel : function()
28950 this.delegates = [];
28952 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28959 renderPreview : function(file)
28961 if(typeof(file.target) != 'undefined' && file.target){
28965 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
28967 var previewEl = this.managerEl.createChild({
28969 cls : 'roo-document-manager-preview',
28973 tooltip : file[this.toolTipName],
28974 cls : 'roo-document-manager-thumb',
28975 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
28980 html : '<i class="fa fa-times-circle"></i>'
28985 var close = previewEl.select('button.close', true).first();
28987 close.on('click', this.onRemove, this, file);
28989 file.target = previewEl;
28991 var image = previewEl.select('img', true).first();
28995 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28997 image.on('click', this.onClick, this, file);
29003 onPreviewLoad : function(file, image)
29005 if(typeof(file.target) == 'undefined' || !file.target){
29009 var width = image.dom.naturalWidth || image.dom.width;
29010 var height = image.dom.naturalHeight || image.dom.height;
29012 if(width > height){
29013 file.target.addClass('wide');
29017 file.target.addClass('tall');
29022 uploadFromSource : function(file, crop)
29024 this.xhr = new XMLHttpRequest();
29026 this.managerEl.createChild({
29028 cls : 'roo-document-manager-loading',
29032 tooltip : file.name,
29033 cls : 'roo-document-manager-thumb',
29034 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29040 this.xhr.open(this.method, this.url, true);
29043 "Accept": "application/json",
29044 "Cache-Control": "no-cache",
29045 "X-Requested-With": "XMLHttpRequest"
29048 for (var headerName in headers) {
29049 var headerValue = headers[headerName];
29051 this.xhr.setRequestHeader(headerName, headerValue);
29057 this.xhr.onload = function()
29059 _this.xhrOnLoad(_this.xhr);
29062 this.xhr.onerror = function()
29064 _this.xhrOnError(_this.xhr);
29067 var formData = new FormData();
29069 formData.append('returnHTML', 'NO');
29071 formData.append('crop', crop);
29073 if(typeof(file.filename) != 'undefined'){
29074 formData.append('filename', file.filename);
29077 if(typeof(file.mimetype) != 'undefined'){
29078 formData.append('mimetype', file.mimetype);
29083 if(this.fireEvent('prepare', this, formData) != false){
29084 this.xhr.send(formData);
29094 * @class Roo.bootstrap.DocumentViewer
29095 * @extends Roo.bootstrap.Component
29096 * Bootstrap DocumentViewer class
29097 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29098 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29101 * Create a new DocumentViewer
29102 * @param {Object} config The config object
29105 Roo.bootstrap.DocumentViewer = function(config){
29106 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29111 * Fire after initEvent
29112 * @param {Roo.bootstrap.DocumentViewer} this
29118 * @param {Roo.bootstrap.DocumentViewer} this
29123 * Fire after download button
29124 * @param {Roo.bootstrap.DocumentViewer} this
29129 * Fire after trash button
29130 * @param {Roo.bootstrap.DocumentViewer} this
29137 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29139 showDownload : true,
29143 getAutoCreate : function()
29147 cls : 'roo-document-viewer',
29151 cls : 'roo-document-viewer-body',
29155 cls : 'roo-document-viewer-thumb',
29159 cls : 'roo-document-viewer-image'
29167 cls : 'roo-document-viewer-footer',
29170 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29174 cls : 'btn-group roo-document-viewer-download',
29178 cls : 'btn btn-default',
29179 html : '<i class="fa fa-download"></i>'
29185 cls : 'btn-group roo-document-viewer-trash',
29189 cls : 'btn btn-default',
29190 html : '<i class="fa fa-trash"></i>'
29203 initEvents : function()
29205 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29206 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29208 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29209 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29211 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29212 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29214 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29215 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29217 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29218 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29220 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29221 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29223 this.bodyEl.on('click', this.onClick, this);
29224 this.downloadBtn.on('click', this.onDownload, this);
29225 this.trashBtn.on('click', this.onTrash, this);
29227 this.downloadBtn.hide();
29228 this.trashBtn.hide();
29230 if(this.showDownload){
29231 this.downloadBtn.show();
29234 if(this.showTrash){
29235 this.trashBtn.show();
29238 if(!this.showDownload && !this.showTrash) {
29239 this.footerEl.hide();
29244 initial : function()
29246 this.fireEvent('initial', this);
29250 onClick : function(e)
29252 e.preventDefault();
29254 this.fireEvent('click', this);
29257 onDownload : function(e)
29259 e.preventDefault();
29261 this.fireEvent('download', this);
29264 onTrash : function(e)
29266 e.preventDefault();
29268 this.fireEvent('trash', this);
29280 * @class Roo.bootstrap.NavProgressBar
29281 * @extends Roo.bootstrap.Component
29282 * Bootstrap NavProgressBar class
29285 * Create a new nav progress bar
29286 * @param {Object} config The config object
29289 Roo.bootstrap.NavProgressBar = function(config){
29290 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29292 this.bullets = this.bullets || [];
29294 // Roo.bootstrap.NavProgressBar.register(this);
29298 * Fires when the active item changes
29299 * @param {Roo.bootstrap.NavProgressBar} this
29300 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29301 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29308 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29313 getAutoCreate : function()
29315 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29319 cls : 'roo-navigation-bar-group',
29323 cls : 'roo-navigation-top-bar'
29327 cls : 'roo-navigation-bullets-bar',
29331 cls : 'roo-navigation-bar'
29338 cls : 'roo-navigation-bottom-bar'
29348 initEvents: function()
29353 onRender : function(ct, position)
29355 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29357 if(this.bullets.length){
29358 Roo.each(this.bullets, function(b){
29367 addItem : function(cfg)
29369 var item = new Roo.bootstrap.NavProgressItem(cfg);
29371 item.parentId = this.id;
29372 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29375 var top = new Roo.bootstrap.Element({
29377 cls : 'roo-navigation-bar-text'
29380 var bottom = new Roo.bootstrap.Element({
29382 cls : 'roo-navigation-bar-text'
29385 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29386 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29388 var topText = new Roo.bootstrap.Element({
29390 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29393 var bottomText = new Roo.bootstrap.Element({
29395 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29398 topText.onRender(top.el, null);
29399 bottomText.onRender(bottom.el, null);
29402 item.bottomEl = bottom;
29405 this.barItems.push(item);
29410 getActive : function()
29412 var active = false;
29414 Roo.each(this.barItems, function(v){
29416 if (!v.isActive()) {
29428 setActiveItem : function(item)
29432 Roo.each(this.barItems, function(v){
29433 if (v.rid == item.rid) {
29437 if (v.isActive()) {
29438 v.setActive(false);
29443 item.setActive(true);
29445 this.fireEvent('changed', this, item, prev);
29448 getBarItem: function(rid)
29452 Roo.each(this.barItems, function(e) {
29453 if (e.rid != rid) {
29464 indexOfItem : function(item)
29468 Roo.each(this.barItems, function(v, i){
29470 if (v.rid != item.rid) {
29481 setActiveNext : function()
29483 var i = this.indexOfItem(this.getActive());
29485 if (i > this.barItems.length) {
29489 this.setActiveItem(this.barItems[i+1]);
29492 setActivePrev : function()
29494 var i = this.indexOfItem(this.getActive());
29500 this.setActiveItem(this.barItems[i-1]);
29503 format : function()
29505 if(!this.barItems.length){
29509 var width = 100 / this.barItems.length;
29511 Roo.each(this.barItems, function(i){
29512 i.el.setStyle('width', width + '%');
29513 i.topEl.el.setStyle('width', width + '%');
29514 i.bottomEl.el.setStyle('width', width + '%');
29523 * Nav Progress Item
29528 * @class Roo.bootstrap.NavProgressItem
29529 * @extends Roo.bootstrap.Component
29530 * Bootstrap NavProgressItem class
29531 * @cfg {String} rid the reference id
29532 * @cfg {Boolean} active (true|false) Is item active default false
29533 * @cfg {Boolean} disabled (true|false) Is item active default false
29534 * @cfg {String} html
29535 * @cfg {String} position (top|bottom) text position default bottom
29536 * @cfg {String} icon show icon instead of number
29539 * Create a new NavProgressItem
29540 * @param {Object} config The config object
29542 Roo.bootstrap.NavProgressItem = function(config){
29543 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29548 * The raw click event for the entire grid.
29549 * @param {Roo.bootstrap.NavProgressItem} this
29550 * @param {Roo.EventObject} e
29557 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29563 position : 'bottom',
29566 getAutoCreate : function()
29568 var iconCls = 'roo-navigation-bar-item-icon';
29570 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29574 cls: 'roo-navigation-bar-item',
29584 cfg.cls += ' active';
29587 cfg.cls += ' disabled';
29593 disable : function()
29595 this.setDisabled(true);
29598 enable : function()
29600 this.setDisabled(false);
29603 initEvents: function()
29605 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29607 this.iconEl.on('click', this.onClick, this);
29610 onClick : function(e)
29612 e.preventDefault();
29618 if(this.fireEvent('click', this, e) === false){
29622 this.parent().setActiveItem(this);
29625 isActive: function ()
29627 return this.active;
29630 setActive : function(state)
29632 if(this.active == state){
29636 this.active = state;
29639 this.el.addClass('active');
29643 this.el.removeClass('active');
29648 setDisabled : function(state)
29650 if(this.disabled == state){
29654 this.disabled = state;
29657 this.el.addClass('disabled');
29661 this.el.removeClass('disabled');
29664 tooltipEl : function()
29666 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29679 * @class Roo.bootstrap.FieldLabel
29680 * @extends Roo.bootstrap.Component
29681 * Bootstrap FieldLabel class
29682 * @cfg {String} html contents of the element
29683 * @cfg {String} tag tag of the element default label
29684 * @cfg {String} cls class of the element
29685 * @cfg {String} target label target
29686 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29687 * @cfg {String} invalidClass default "text-warning"
29688 * @cfg {String} validClass default "text-success"
29689 * @cfg {String} iconTooltip default "This field is required"
29690 * @cfg {String} indicatorpos (left|right) default left
29693 * Create a new FieldLabel
29694 * @param {Object} config The config object
29697 Roo.bootstrap.FieldLabel = function(config){
29698 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29703 * Fires after the field has been marked as invalid.
29704 * @param {Roo.form.FieldLabel} this
29705 * @param {String} msg The validation message
29710 * Fires after the field has been validated with no errors.
29711 * @param {Roo.form.FieldLabel} this
29717 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29724 invalidClass : 'has-warning',
29725 validClass : 'has-success',
29726 iconTooltip : 'This field is required',
29727 indicatorpos : 'left',
29729 getAutoCreate : function(){
29733 cls : 'roo-bootstrap-field-label ' + this.cls,
29738 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29739 tooltip : this.iconTooltip
29748 if(this.indicatorpos == 'right'){
29751 cls : 'roo-bootstrap-field-label ' + this.cls,
29760 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29761 tooltip : this.iconTooltip
29770 initEvents: function()
29772 Roo.bootstrap.Element.superclass.initEvents.call(this);
29774 this.indicator = this.indicatorEl();
29776 if(this.indicator){
29777 this.indicator.removeClass('visible');
29778 this.indicator.addClass('invisible');
29781 Roo.bootstrap.FieldLabel.register(this);
29784 indicatorEl : function()
29786 var indicator = this.el.select('i.roo-required-indicator',true).first();
29797 * Mark this field as valid
29799 markValid : function()
29801 if(this.indicator){
29802 this.indicator.removeClass('visible');
29803 this.indicator.addClass('invisible');
29806 this.el.removeClass(this.invalidClass);
29808 this.el.addClass(this.validClass);
29810 this.fireEvent('valid', this);
29814 * Mark this field as invalid
29815 * @param {String} msg The validation message
29817 markInvalid : function(msg)
29819 if(this.indicator){
29820 this.indicator.removeClass('invisible');
29821 this.indicator.addClass('visible');
29824 this.el.removeClass(this.validClass);
29826 this.el.addClass(this.invalidClass);
29828 this.fireEvent('invalid', this, msg);
29834 Roo.apply(Roo.bootstrap.FieldLabel, {
29839 * register a FieldLabel Group
29840 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29842 register : function(label)
29844 if(this.groups.hasOwnProperty(label.target)){
29848 this.groups[label.target] = label;
29852 * fetch a FieldLabel Group based on the target
29853 * @param {string} target
29854 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29856 get: function(target) {
29857 if (typeof(this.groups[target]) == 'undefined') {
29861 return this.groups[target] ;
29870 * page DateSplitField.
29876 * @class Roo.bootstrap.DateSplitField
29877 * @extends Roo.bootstrap.Component
29878 * Bootstrap DateSplitField class
29879 * @cfg {string} fieldLabel - the label associated
29880 * @cfg {Number} labelWidth set the width of label (0-12)
29881 * @cfg {String} labelAlign (top|left)
29882 * @cfg {Boolean} dayAllowBlank (true|false) default false
29883 * @cfg {Boolean} monthAllowBlank (true|false) default false
29884 * @cfg {Boolean} yearAllowBlank (true|false) default false
29885 * @cfg {string} dayPlaceholder
29886 * @cfg {string} monthPlaceholder
29887 * @cfg {string} yearPlaceholder
29888 * @cfg {string} dayFormat default 'd'
29889 * @cfg {string} monthFormat default 'm'
29890 * @cfg {string} yearFormat default 'Y'
29891 * @cfg {Number} labellg set the width of label (1-12)
29892 * @cfg {Number} labelmd set the width of label (1-12)
29893 * @cfg {Number} labelsm set the width of label (1-12)
29894 * @cfg {Number} labelxs set the width of label (1-12)
29898 * Create a new DateSplitField
29899 * @param {Object} config The config object
29902 Roo.bootstrap.DateSplitField = function(config){
29903 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29909 * getting the data of years
29910 * @param {Roo.bootstrap.DateSplitField} this
29911 * @param {Object} years
29916 * getting the data of days
29917 * @param {Roo.bootstrap.DateSplitField} this
29918 * @param {Object} days
29923 * Fires after the field has been marked as invalid.
29924 * @param {Roo.form.Field} this
29925 * @param {String} msg The validation message
29930 * Fires after the field has been validated with no errors.
29931 * @param {Roo.form.Field} this
29937 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29940 labelAlign : 'top',
29942 dayAllowBlank : false,
29943 monthAllowBlank : false,
29944 yearAllowBlank : false,
29945 dayPlaceholder : '',
29946 monthPlaceholder : '',
29947 yearPlaceholder : '',
29951 isFormField : true,
29957 getAutoCreate : function()
29961 cls : 'row roo-date-split-field-group',
29966 cls : 'form-hidden-field roo-date-split-field-group-value',
29972 var labelCls = 'col-md-12';
29973 var contentCls = 'col-md-4';
29975 if(this.fieldLabel){
29979 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29983 html : this.fieldLabel
29988 if(this.labelAlign == 'left'){
29990 if(this.labelWidth > 12){
29991 label.style = "width: " + this.labelWidth + 'px';
29994 if(this.labelWidth < 13 && this.labelmd == 0){
29995 this.labelmd = this.labelWidth;
29998 if(this.labellg > 0){
29999 labelCls = ' col-lg-' + this.labellg;
30000 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30003 if(this.labelmd > 0){
30004 labelCls = ' col-md-' + this.labelmd;
30005 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30008 if(this.labelsm > 0){
30009 labelCls = ' col-sm-' + this.labelsm;
30010 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30013 if(this.labelxs > 0){
30014 labelCls = ' col-xs-' + this.labelxs;
30015 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30019 label.cls += ' ' + labelCls;
30021 cfg.cn.push(label);
30024 Roo.each(['day', 'month', 'year'], function(t){
30027 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30034 inputEl: function ()
30036 return this.el.select('.roo-date-split-field-group-value', true).first();
30039 onRender : function(ct, position)
30043 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30045 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30047 this.dayField = new Roo.bootstrap.ComboBox({
30048 allowBlank : this.dayAllowBlank,
30049 alwaysQuery : true,
30050 displayField : 'value',
30053 forceSelection : true,
30055 placeholder : this.dayPlaceholder,
30056 selectOnFocus : true,
30057 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30058 triggerAction : 'all',
30060 valueField : 'value',
30061 store : new Roo.data.SimpleStore({
30062 data : (function() {
30064 _this.fireEvent('days', _this, days);
30067 fields : [ 'value' ]
30070 select : function (_self, record, index)
30072 _this.setValue(_this.getValue());
30077 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30079 this.monthField = new Roo.bootstrap.MonthField({
30080 after : '<i class=\"fa fa-calendar\"></i>',
30081 allowBlank : this.monthAllowBlank,
30082 placeholder : this.monthPlaceholder,
30085 render : function (_self)
30087 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30088 e.preventDefault();
30092 select : function (_self, oldvalue, newvalue)
30094 _this.setValue(_this.getValue());
30099 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30101 this.yearField = new Roo.bootstrap.ComboBox({
30102 allowBlank : this.yearAllowBlank,
30103 alwaysQuery : true,
30104 displayField : 'value',
30107 forceSelection : true,
30109 placeholder : this.yearPlaceholder,
30110 selectOnFocus : true,
30111 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30112 triggerAction : 'all',
30114 valueField : 'value',
30115 store : new Roo.data.SimpleStore({
30116 data : (function() {
30118 _this.fireEvent('years', _this, years);
30121 fields : [ 'value' ]
30124 select : function (_self, record, index)
30126 _this.setValue(_this.getValue());
30131 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30134 setValue : function(v, format)
30136 this.inputEl.dom.value = v;
30138 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30140 var d = Date.parseDate(v, f);
30147 this.setDay(d.format(this.dayFormat));
30148 this.setMonth(d.format(this.monthFormat));
30149 this.setYear(d.format(this.yearFormat));
30156 setDay : function(v)
30158 this.dayField.setValue(v);
30159 this.inputEl.dom.value = this.getValue();
30164 setMonth : function(v)
30166 this.monthField.setValue(v, true);
30167 this.inputEl.dom.value = this.getValue();
30172 setYear : function(v)
30174 this.yearField.setValue(v);
30175 this.inputEl.dom.value = this.getValue();
30180 getDay : function()
30182 return this.dayField.getValue();
30185 getMonth : function()
30187 return this.monthField.getValue();
30190 getYear : function()
30192 return this.yearField.getValue();
30195 getValue : function()
30197 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30199 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30209 this.inputEl.dom.value = '';
30214 validate : function()
30216 var d = this.dayField.validate();
30217 var m = this.monthField.validate();
30218 var y = this.yearField.validate();
30223 (!this.dayAllowBlank && !d) ||
30224 (!this.monthAllowBlank && !m) ||
30225 (!this.yearAllowBlank && !y)
30230 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30239 this.markInvalid();
30244 markValid : function()
30247 var label = this.el.select('label', true).first();
30248 var icon = this.el.select('i.fa-star', true).first();
30254 this.fireEvent('valid', this);
30258 * Mark this field as invalid
30259 * @param {String} msg The validation message
30261 markInvalid : function(msg)
30264 var label = this.el.select('label', true).first();
30265 var icon = this.el.select('i.fa-star', true).first();
30267 if(label && !icon){
30268 this.el.select('.roo-date-split-field-label', true).createChild({
30270 cls : 'text-danger fa fa-lg fa-star',
30271 tooltip : 'This field is required',
30272 style : 'margin-right:5px;'
30276 this.fireEvent('invalid', this, msg);
30279 clearInvalid : function()
30281 var label = this.el.select('label', true).first();
30282 var icon = this.el.select('i.fa-star', true).first();
30288 this.fireEvent('valid', this);
30291 getName: function()
30301 * http://masonry.desandro.com
30303 * The idea is to render all the bricks based on vertical width...
30305 * The original code extends 'outlayer' - we might need to use that....
30311 * @class Roo.bootstrap.LayoutMasonry
30312 * @extends Roo.bootstrap.Component
30313 * Bootstrap Layout Masonry class
30316 * Create a new Element
30317 * @param {Object} config The config object
30320 Roo.bootstrap.LayoutMasonry = function(config){
30322 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30326 Roo.bootstrap.LayoutMasonry.register(this);
30332 * Fire after layout the items
30333 * @param {Roo.bootstrap.LayoutMasonry} this
30334 * @param {Roo.EventObject} e
30341 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30344 * @cfg {Boolean} isLayoutInstant = no animation?
30346 isLayoutInstant : false, // needed?
30349 * @cfg {Number} boxWidth width of the columns
30354 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30359 * @cfg {Number} padWidth padding below box..
30364 * @cfg {Number} gutter gutter width..
30369 * @cfg {Number} maxCols maximum number of columns
30375 * @cfg {Boolean} isAutoInitial defalut true
30377 isAutoInitial : true,
30382 * @cfg {Boolean} isHorizontal defalut false
30384 isHorizontal : false,
30386 currentSize : null,
30392 bricks: null, //CompositeElement
30396 _isLayoutInited : false,
30398 // isAlternative : false, // only use for vertical layout...
30401 * @cfg {Number} alternativePadWidth padding below box..
30403 alternativePadWidth : 50,
30405 selectedBrick : [],
30407 getAutoCreate : function(){
30409 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30413 cls: 'blog-masonary-wrapper ' + this.cls,
30415 cls : 'mas-boxes masonary'
30422 getChildContainer: function( )
30424 if (this.boxesEl) {
30425 return this.boxesEl;
30428 this.boxesEl = this.el.select('.mas-boxes').first();
30430 return this.boxesEl;
30434 initEvents : function()
30438 if(this.isAutoInitial){
30439 Roo.log('hook children rendered');
30440 this.on('childrenrendered', function() {
30441 Roo.log('children rendered');
30447 initial : function()
30449 this.selectedBrick = [];
30451 this.currentSize = this.el.getBox(true);
30453 Roo.EventManager.onWindowResize(this.resize, this);
30455 if(!this.isAutoInitial){
30463 //this.layout.defer(500,this);
30467 resize : function()
30469 var cs = this.el.getBox(true);
30472 this.currentSize.width == cs.width &&
30473 this.currentSize.x == cs.x &&
30474 this.currentSize.height == cs.height &&
30475 this.currentSize.y == cs.y
30477 Roo.log("no change in with or X or Y");
30481 this.currentSize = cs;
30487 layout : function()
30489 this._resetLayout();
30491 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30493 this.layoutItems( isInstant );
30495 this._isLayoutInited = true;
30497 this.fireEvent('layout', this);
30501 _resetLayout : function()
30503 if(this.isHorizontal){
30504 this.horizontalMeasureColumns();
30508 this.verticalMeasureColumns();
30512 verticalMeasureColumns : function()
30514 this.getContainerWidth();
30516 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30517 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30521 var boxWidth = this.boxWidth + this.padWidth;
30523 if(this.containerWidth < this.boxWidth){
30524 boxWidth = this.containerWidth
30527 var containerWidth = this.containerWidth;
30529 var cols = Math.floor(containerWidth / boxWidth);
30531 this.cols = Math.max( cols, 1 );
30533 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30535 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30537 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30539 this.colWidth = boxWidth + avail - this.padWidth;
30541 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30542 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30545 horizontalMeasureColumns : function()
30547 this.getContainerWidth();
30549 var boxWidth = this.boxWidth;
30551 if(this.containerWidth < boxWidth){
30552 boxWidth = this.containerWidth;
30555 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30557 this.el.setHeight(boxWidth);
30561 getContainerWidth : function()
30563 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30566 layoutItems : function( isInstant )
30568 Roo.log(this.bricks);
30570 var items = Roo.apply([], this.bricks);
30572 if(this.isHorizontal){
30573 this._horizontalLayoutItems( items , isInstant );
30577 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30578 // this._verticalAlternativeLayoutItems( items , isInstant );
30582 this._verticalLayoutItems( items , isInstant );
30586 _verticalLayoutItems : function ( items , isInstant)
30588 if ( !items || !items.length ) {
30593 ['xs', 'xs', 'xs', 'tall'],
30594 ['xs', 'xs', 'tall'],
30595 ['xs', 'xs', 'sm'],
30596 ['xs', 'xs', 'xs'],
30602 ['sm', 'xs', 'xs'],
30606 ['tall', 'xs', 'xs', 'xs'],
30607 ['tall', 'xs', 'xs'],
30619 Roo.each(items, function(item, k){
30621 switch (item.size) {
30622 // these layouts take up a full box,
30633 boxes.push([item]);
30656 var filterPattern = function(box, length)
30664 var pattern = box.slice(0, length);
30668 Roo.each(pattern, function(i){
30669 format.push(i.size);
30672 Roo.each(standard, function(s){
30674 if(String(s) != String(format)){
30683 if(!match && length == 1){
30688 filterPattern(box, length - 1);
30692 queue.push(pattern);
30694 box = box.slice(length, box.length);
30696 filterPattern(box, 4);
30702 Roo.each(boxes, function(box, k){
30708 if(box.length == 1){
30713 filterPattern(box, 4);
30717 this._processVerticalLayoutQueue( queue, isInstant );
30721 // _verticalAlternativeLayoutItems : function( items , isInstant )
30723 // if ( !items || !items.length ) {
30727 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30731 _horizontalLayoutItems : function ( items , isInstant)
30733 if ( !items || !items.length || items.length < 3) {
30739 var eItems = items.slice(0, 3);
30741 items = items.slice(3, items.length);
30744 ['xs', 'xs', 'xs', 'wide'],
30745 ['xs', 'xs', 'wide'],
30746 ['xs', 'xs', 'sm'],
30747 ['xs', 'xs', 'xs'],
30753 ['sm', 'xs', 'xs'],
30757 ['wide', 'xs', 'xs', 'xs'],
30758 ['wide', 'xs', 'xs'],
30771 Roo.each(items, function(item, k){
30773 switch (item.size) {
30784 boxes.push([item]);
30808 var filterPattern = function(box, length)
30816 var pattern = box.slice(0, length);
30820 Roo.each(pattern, function(i){
30821 format.push(i.size);
30824 Roo.each(standard, function(s){
30826 if(String(s) != String(format)){
30835 if(!match && length == 1){
30840 filterPattern(box, length - 1);
30844 queue.push(pattern);
30846 box = box.slice(length, box.length);
30848 filterPattern(box, 4);
30854 Roo.each(boxes, function(box, k){
30860 if(box.length == 1){
30865 filterPattern(box, 4);
30872 var pos = this.el.getBox(true);
30876 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30878 var hit_end = false;
30880 Roo.each(queue, function(box){
30884 Roo.each(box, function(b){
30886 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30896 Roo.each(box, function(b){
30898 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30901 mx = Math.max(mx, b.x);
30905 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30909 Roo.each(box, function(b){
30911 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30925 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30928 /** Sets position of item in DOM
30929 * @param {Element} item
30930 * @param {Number} x - horizontal position
30931 * @param {Number} y - vertical position
30932 * @param {Boolean} isInstant - disables transitions
30934 _processVerticalLayoutQueue : function( queue, isInstant )
30936 var pos = this.el.getBox(true);
30941 for (var i = 0; i < this.cols; i++){
30945 Roo.each(queue, function(box, k){
30947 var col = k % this.cols;
30949 Roo.each(box, function(b,kk){
30951 b.el.position('absolute');
30953 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30954 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30956 if(b.size == 'md-left' || b.size == 'md-right'){
30957 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30958 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30961 b.el.setWidth(width);
30962 b.el.setHeight(height);
30964 b.el.select('iframe',true).setSize(width,height);
30968 for (var i = 0; i < this.cols; i++){
30970 if(maxY[i] < maxY[col]){
30975 col = Math.min(col, i);
30979 x = pos.x + col * (this.colWidth + this.padWidth);
30983 var positions = [];
30985 switch (box.length){
30987 positions = this.getVerticalOneBoxColPositions(x, y, box);
30990 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30993 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30996 positions = this.getVerticalFourBoxColPositions(x, y, box);
31002 Roo.each(box, function(b,kk){
31004 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31006 var sz = b.el.getSize();
31008 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31016 for (var i = 0; i < this.cols; i++){
31017 mY = Math.max(mY, maxY[i]);
31020 this.el.setHeight(mY - pos.y);
31024 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31026 // var pos = this.el.getBox(true);
31029 // var maxX = pos.right;
31031 // var maxHeight = 0;
31033 // Roo.each(items, function(item, k){
31037 // item.el.position('absolute');
31039 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31041 // item.el.setWidth(width);
31043 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31045 // item.el.setHeight(height);
31048 // item.el.setXY([x, y], isInstant ? false : true);
31050 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31053 // y = y + height + this.alternativePadWidth;
31055 // maxHeight = maxHeight + height + this.alternativePadWidth;
31059 // this.el.setHeight(maxHeight);
31063 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31065 var pos = this.el.getBox(true);
31070 var maxX = pos.right;
31072 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31074 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31076 Roo.each(queue, function(box, k){
31078 Roo.each(box, function(b, kk){
31080 b.el.position('absolute');
31082 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31083 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31085 if(b.size == 'md-left' || b.size == 'md-right'){
31086 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31087 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31090 b.el.setWidth(width);
31091 b.el.setHeight(height);
31099 var positions = [];
31101 switch (box.length){
31103 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31106 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31109 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31112 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31118 Roo.each(box, function(b,kk){
31120 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31122 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31130 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31132 Roo.each(eItems, function(b,k){
31134 b.size = (k == 0) ? 'sm' : 'xs';
31135 b.x = (k == 0) ? 2 : 1;
31136 b.y = (k == 0) ? 2 : 1;
31138 b.el.position('absolute');
31140 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31142 b.el.setWidth(width);
31144 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31146 b.el.setHeight(height);
31150 var positions = [];
31153 x : maxX - this.unitWidth * 2 - this.gutter,
31158 x : maxX - this.unitWidth,
31159 y : minY + (this.unitWidth + this.gutter) * 2
31163 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31167 Roo.each(eItems, function(b,k){
31169 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31175 getVerticalOneBoxColPositions : function(x, y, box)
31179 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31181 if(box[0].size == 'md-left'){
31185 if(box[0].size == 'md-right'){
31190 x : x + (this.unitWidth + this.gutter) * rand,
31197 getVerticalTwoBoxColPositions : function(x, y, box)
31201 if(box[0].size == 'xs'){
31205 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31209 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31223 x : x + (this.unitWidth + this.gutter) * 2,
31224 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31231 getVerticalThreeBoxColPositions : function(x, y, box)
31235 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31243 x : x + (this.unitWidth + this.gutter) * 1,
31248 x : x + (this.unitWidth + this.gutter) * 2,
31256 if(box[0].size == 'xs' && box[1].size == 'xs'){
31265 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31269 x : x + (this.unitWidth + this.gutter) * 1,
31283 x : x + (this.unitWidth + this.gutter) * 2,
31288 x : x + (this.unitWidth + this.gutter) * 2,
31289 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31296 getVerticalFourBoxColPositions : function(x, y, box)
31300 if(box[0].size == 'xs'){
31309 y : y + (this.unitHeight + this.gutter) * 1
31314 y : y + (this.unitHeight + this.gutter) * 2
31318 x : x + (this.unitWidth + this.gutter) * 1,
31332 x : x + (this.unitWidth + this.gutter) * 2,
31337 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31338 y : y + (this.unitHeight + this.gutter) * 1
31342 x : x + (this.unitWidth + this.gutter) * 2,
31343 y : y + (this.unitWidth + this.gutter) * 2
31350 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31354 if(box[0].size == 'md-left'){
31356 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31363 if(box[0].size == 'md-right'){
31365 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31366 y : minY + (this.unitWidth + this.gutter) * 1
31372 var rand = Math.floor(Math.random() * (4 - box[0].y));
31375 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31376 y : minY + (this.unitWidth + this.gutter) * rand
31383 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31387 if(box[0].size == 'xs'){
31390 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31395 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31396 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31404 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31409 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31410 y : minY + (this.unitWidth + this.gutter) * 2
31417 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31421 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31424 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31429 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31430 y : minY + (this.unitWidth + this.gutter) * 1
31434 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31435 y : minY + (this.unitWidth + this.gutter) * 2
31442 if(box[0].size == 'xs' && box[1].size == 'xs'){
31445 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31450 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31455 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31456 y : minY + (this.unitWidth + this.gutter) * 1
31464 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31469 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31470 y : minY + (this.unitWidth + this.gutter) * 2
31474 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31475 y : minY + (this.unitWidth + this.gutter) * 2
31482 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31486 if(box[0].size == 'xs'){
31489 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31494 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31499 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),
31504 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31505 y : minY + (this.unitWidth + this.gutter) * 1
31513 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31518 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31519 y : minY + (this.unitWidth + this.gutter) * 2
31523 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31524 y : minY + (this.unitWidth + this.gutter) * 2
31528 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),
31529 y : minY + (this.unitWidth + this.gutter) * 2
31537 * remove a Masonry Brick
31538 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31540 removeBrick : function(brick_id)
31546 for (var i = 0; i<this.bricks.length; i++) {
31547 if (this.bricks[i].id == brick_id) {
31548 this.bricks.splice(i,1);
31549 this.el.dom.removeChild(Roo.get(brick_id).dom);
31556 * adds a Masonry Brick
31557 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31559 addBrick : function(cfg)
31561 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31562 //this.register(cn);
31563 cn.parentId = this.id;
31564 cn.onRender(this.el, null);
31569 * register a Masonry Brick
31570 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31573 register : function(brick)
31575 this.bricks.push(brick);
31576 brick.masonryId = this.id;
31580 * clear all the Masonry Brick
31582 clearAll : function()
31585 //this.getChildContainer().dom.innerHTML = "";
31586 this.el.dom.innerHTML = '';
31589 getSelected : function()
31591 if (!this.selectedBrick) {
31595 return this.selectedBrick;
31599 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31603 * register a Masonry Layout
31604 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31607 register : function(layout)
31609 this.groups[layout.id] = layout;
31612 * fetch a Masonry Layout based on the masonry layout ID
31613 * @param {string} the masonry layout to add
31614 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31617 get: function(layout_id) {
31618 if (typeof(this.groups[layout_id]) == 'undefined') {
31621 return this.groups[layout_id] ;
31633 * http://masonry.desandro.com
31635 * The idea is to render all the bricks based on vertical width...
31637 * The original code extends 'outlayer' - we might need to use that....
31643 * @class Roo.bootstrap.LayoutMasonryAuto
31644 * @extends Roo.bootstrap.Component
31645 * Bootstrap Layout Masonry class
31648 * Create a new Element
31649 * @param {Object} config The config object
31652 Roo.bootstrap.LayoutMasonryAuto = function(config){
31653 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31656 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31659 * @cfg {Boolean} isFitWidth - resize the width..
31661 isFitWidth : false, // options..
31663 * @cfg {Boolean} isOriginLeft = left align?
31665 isOriginLeft : true,
31667 * @cfg {Boolean} isOriginTop = top align?
31669 isOriginTop : false,
31671 * @cfg {Boolean} isLayoutInstant = no animation?
31673 isLayoutInstant : false, // needed?
31675 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31677 isResizingContainer : true,
31679 * @cfg {Number} columnWidth width of the columns
31685 * @cfg {Number} maxCols maximum number of columns
31690 * @cfg {Number} padHeight padding below box..
31696 * @cfg {Boolean} isAutoInitial defalut true
31699 isAutoInitial : true,
31705 initialColumnWidth : 0,
31706 currentSize : null,
31708 colYs : null, // array.
31715 bricks: null, //CompositeElement
31716 cols : 0, // array?
31717 // element : null, // wrapped now this.el
31718 _isLayoutInited : null,
31721 getAutoCreate : function(){
31725 cls: 'blog-masonary-wrapper ' + this.cls,
31727 cls : 'mas-boxes masonary'
31734 getChildContainer: function( )
31736 if (this.boxesEl) {
31737 return this.boxesEl;
31740 this.boxesEl = this.el.select('.mas-boxes').first();
31742 return this.boxesEl;
31746 initEvents : function()
31750 if(this.isAutoInitial){
31751 Roo.log('hook children rendered');
31752 this.on('childrenrendered', function() {
31753 Roo.log('children rendered');
31760 initial : function()
31762 this.reloadItems();
31764 this.currentSize = this.el.getBox(true);
31766 /// was window resize... - let's see if this works..
31767 Roo.EventManager.onWindowResize(this.resize, this);
31769 if(!this.isAutoInitial){
31774 this.layout.defer(500,this);
31777 reloadItems: function()
31779 this.bricks = this.el.select('.masonry-brick', true);
31781 this.bricks.each(function(b) {
31782 //Roo.log(b.getSize());
31783 if (!b.attr('originalwidth')) {
31784 b.attr('originalwidth', b.getSize().width);
31789 Roo.log(this.bricks.elements.length);
31792 resize : function()
31795 var cs = this.el.getBox(true);
31797 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31798 Roo.log("no change in with or X");
31801 this.currentSize = cs;
31805 layout : function()
31808 this._resetLayout();
31809 //this._manageStamps();
31811 // don't animate first layout
31812 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31813 this.layoutItems( isInstant );
31815 // flag for initalized
31816 this._isLayoutInited = true;
31819 layoutItems : function( isInstant )
31821 //var items = this._getItemsForLayout( this.items );
31822 // original code supports filtering layout items.. we just ignore it..
31824 this._layoutItems( this.bricks , isInstant );
31826 this._postLayout();
31828 _layoutItems : function ( items , isInstant)
31830 //this.fireEvent( 'layout', this, items );
31833 if ( !items || !items.elements.length ) {
31834 // no items, emit event with empty array
31839 items.each(function(item) {
31840 Roo.log("layout item");
31842 // get x/y object from method
31843 var position = this._getItemLayoutPosition( item );
31845 position.item = item;
31846 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31847 queue.push( position );
31850 this._processLayoutQueue( queue );
31852 /** Sets position of item in DOM
31853 * @param {Element} item
31854 * @param {Number} x - horizontal position
31855 * @param {Number} y - vertical position
31856 * @param {Boolean} isInstant - disables transitions
31858 _processLayoutQueue : function( queue )
31860 for ( var i=0, len = queue.length; i < len; i++ ) {
31861 var obj = queue[i];
31862 obj.item.position('absolute');
31863 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31869 * Any logic you want to do after each layout,
31870 * i.e. size the container
31872 _postLayout : function()
31874 this.resizeContainer();
31877 resizeContainer : function()
31879 if ( !this.isResizingContainer ) {
31882 var size = this._getContainerSize();
31884 this.el.setSize(size.width,size.height);
31885 this.boxesEl.setSize(size.width,size.height);
31891 _resetLayout : function()
31893 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31894 this.colWidth = this.el.getWidth();
31895 //this.gutter = this.el.getWidth();
31897 this.measureColumns();
31903 this.colYs.push( 0 );
31909 measureColumns : function()
31911 this.getContainerWidth();
31912 // if columnWidth is 0, default to outerWidth of first item
31913 if ( !this.columnWidth ) {
31914 var firstItem = this.bricks.first();
31915 Roo.log(firstItem);
31916 this.columnWidth = this.containerWidth;
31917 if (firstItem && firstItem.attr('originalwidth') ) {
31918 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31920 // columnWidth fall back to item of first element
31921 Roo.log("set column width?");
31922 this.initialColumnWidth = this.columnWidth ;
31924 // if first elem has no width, default to size of container
31929 if (this.initialColumnWidth) {
31930 this.columnWidth = this.initialColumnWidth;
31935 // column width is fixed at the top - however if container width get's smaller we should
31938 // this bit calcs how man columns..
31940 var columnWidth = this.columnWidth += this.gutter;
31942 // calculate columns
31943 var containerWidth = this.containerWidth + this.gutter;
31945 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31946 // fix rounding errors, typically with gutters
31947 var excess = columnWidth - containerWidth % columnWidth;
31950 // if overshoot is less than a pixel, round up, otherwise floor it
31951 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31952 cols = Math[ mathMethod ]( cols );
31953 this.cols = Math.max( cols, 1 );
31954 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31956 // padding positioning..
31957 var totalColWidth = this.cols * this.columnWidth;
31958 var padavail = this.containerWidth - totalColWidth;
31959 // so for 2 columns - we need 3 'pads'
31961 var padNeeded = (1+this.cols) * this.padWidth;
31963 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31965 this.columnWidth += padExtra
31966 //this.padWidth = Math.floor(padavail / ( this.cols));
31968 // adjust colum width so that padding is fixed??
31970 // we have 3 columns ... total = width * 3
31971 // we have X left over... that should be used by
31973 //if (this.expandC) {
31981 getContainerWidth : function()
31983 /* // container is parent if fit width
31984 var container = this.isFitWidth ? this.element.parentNode : this.element;
31985 // check that this.size and size are there
31986 // IE8 triggers resize on body size change, so they might not be
31988 var size = getSize( container ); //FIXME
31989 this.containerWidth = size && size.innerWidth; //FIXME
31992 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31996 _getItemLayoutPosition : function( item ) // what is item?
31998 // we resize the item to our columnWidth..
32000 item.setWidth(this.columnWidth);
32001 item.autoBoxAdjust = false;
32003 var sz = item.getSize();
32005 // how many columns does this brick span
32006 var remainder = this.containerWidth % this.columnWidth;
32008 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32009 // round if off by 1 pixel, otherwise use ceil
32010 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32011 colSpan = Math.min( colSpan, this.cols );
32013 // normally this should be '1' as we dont' currently allow multi width columns..
32015 var colGroup = this._getColGroup( colSpan );
32016 // get the minimum Y value from the columns
32017 var minimumY = Math.min.apply( Math, colGroup );
32018 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32020 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32022 // position the brick
32024 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32025 y: this.currentSize.y + minimumY + this.padHeight
32029 // apply setHeight to necessary columns
32030 var setHeight = minimumY + sz.height + this.padHeight;
32031 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32033 var setSpan = this.cols + 1 - colGroup.length;
32034 for ( var i = 0; i < setSpan; i++ ) {
32035 this.colYs[ shortColIndex + i ] = setHeight ;
32042 * @param {Number} colSpan - number of columns the element spans
32043 * @returns {Array} colGroup
32045 _getColGroup : function( colSpan )
32047 if ( colSpan < 2 ) {
32048 // if brick spans only one column, use all the column Ys
32053 // how many different places could this brick fit horizontally
32054 var groupCount = this.cols + 1 - colSpan;
32055 // for each group potential horizontal position
32056 for ( var i = 0; i < groupCount; i++ ) {
32057 // make an array of colY values for that one group
32058 var groupColYs = this.colYs.slice( i, i + colSpan );
32059 // and get the max value of the array
32060 colGroup[i] = Math.max.apply( Math, groupColYs );
32065 _manageStamp : function( stamp )
32067 var stampSize = stamp.getSize();
32068 var offset = stamp.getBox();
32069 // get the columns that this stamp affects
32070 var firstX = this.isOriginLeft ? offset.x : offset.right;
32071 var lastX = firstX + stampSize.width;
32072 var firstCol = Math.floor( firstX / this.columnWidth );
32073 firstCol = Math.max( 0, firstCol );
32075 var lastCol = Math.floor( lastX / this.columnWidth );
32076 // lastCol should not go over if multiple of columnWidth #425
32077 lastCol -= lastX % this.columnWidth ? 0 : 1;
32078 lastCol = Math.min( this.cols - 1, lastCol );
32080 // set colYs to bottom of the stamp
32081 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32084 for ( var i = firstCol; i <= lastCol; i++ ) {
32085 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32090 _getContainerSize : function()
32092 this.maxY = Math.max.apply( Math, this.colYs );
32097 if ( this.isFitWidth ) {
32098 size.width = this._getContainerFitWidth();
32104 _getContainerFitWidth : function()
32106 var unusedCols = 0;
32107 // count unused columns
32110 if ( this.colYs[i] !== 0 ) {
32115 // fit container to columns that have been used
32116 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32119 needsResizeLayout : function()
32121 var previousWidth = this.containerWidth;
32122 this.getContainerWidth();
32123 return previousWidth !== this.containerWidth;
32138 * @class Roo.bootstrap.MasonryBrick
32139 * @extends Roo.bootstrap.Component
32140 * Bootstrap MasonryBrick class
32143 * Create a new MasonryBrick
32144 * @param {Object} config The config object
32147 Roo.bootstrap.MasonryBrick = function(config){
32149 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32151 Roo.bootstrap.MasonryBrick.register(this);
32157 * When a MasonryBrick is clcik
32158 * @param {Roo.bootstrap.MasonryBrick} this
32159 * @param {Roo.EventObject} e
32165 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32168 * @cfg {String} title
32172 * @cfg {String} html
32176 * @cfg {String} bgimage
32180 * @cfg {String} videourl
32184 * @cfg {String} cls
32188 * @cfg {String} href
32192 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32197 * @cfg {String} placetitle (center|bottom)
32202 * @cfg {Boolean} isFitContainer defalut true
32204 isFitContainer : true,
32207 * @cfg {Boolean} preventDefault defalut false
32209 preventDefault : false,
32212 * @cfg {Boolean} inverse defalut false
32214 maskInverse : false,
32216 getAutoCreate : function()
32218 if(!this.isFitContainer){
32219 return this.getSplitAutoCreate();
32222 var cls = 'masonry-brick masonry-brick-full';
32224 if(this.href.length){
32225 cls += ' masonry-brick-link';
32228 if(this.bgimage.length){
32229 cls += ' masonry-brick-image';
32232 if(this.maskInverse){
32233 cls += ' mask-inverse';
32236 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32237 cls += ' enable-mask';
32241 cls += ' masonry-' + this.size + '-brick';
32244 if(this.placetitle.length){
32246 switch (this.placetitle) {
32248 cls += ' masonry-center-title';
32251 cls += ' masonry-bottom-title';
32258 if(!this.html.length && !this.bgimage.length){
32259 cls += ' masonry-center-title';
32262 if(!this.html.length && this.bgimage.length){
32263 cls += ' masonry-bottom-title';
32268 cls += ' ' + this.cls;
32272 tag: (this.href.length) ? 'a' : 'div',
32277 cls: 'masonry-brick-mask'
32281 cls: 'masonry-brick-paragraph',
32287 if(this.href.length){
32288 cfg.href = this.href;
32291 var cn = cfg.cn[1].cn;
32293 if(this.title.length){
32296 cls: 'masonry-brick-title',
32301 if(this.html.length){
32304 cls: 'masonry-brick-text',
32309 if (!this.title.length && !this.html.length) {
32310 cfg.cn[1].cls += ' hide';
32313 if(this.bgimage.length){
32316 cls: 'masonry-brick-image-view',
32321 if(this.videourl.length){
32322 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32323 // youtube support only?
32326 cls: 'masonry-brick-image-view',
32329 allowfullscreen : true
32337 getSplitAutoCreate : function()
32339 var cls = 'masonry-brick masonry-brick-split';
32341 if(this.href.length){
32342 cls += ' masonry-brick-link';
32345 if(this.bgimage.length){
32346 cls += ' masonry-brick-image';
32350 cls += ' masonry-' + this.size + '-brick';
32353 switch (this.placetitle) {
32355 cls += ' masonry-center-title';
32358 cls += ' masonry-bottom-title';
32361 if(!this.bgimage.length){
32362 cls += ' masonry-center-title';
32365 if(this.bgimage.length){
32366 cls += ' masonry-bottom-title';
32372 cls += ' ' + this.cls;
32376 tag: (this.href.length) ? 'a' : 'div',
32381 cls: 'masonry-brick-split-head',
32385 cls: 'masonry-brick-paragraph',
32392 cls: 'masonry-brick-split-body',
32398 if(this.href.length){
32399 cfg.href = this.href;
32402 if(this.title.length){
32403 cfg.cn[0].cn[0].cn.push({
32405 cls: 'masonry-brick-title',
32410 if(this.html.length){
32411 cfg.cn[1].cn.push({
32413 cls: 'masonry-brick-text',
32418 if(this.bgimage.length){
32419 cfg.cn[0].cn.push({
32421 cls: 'masonry-brick-image-view',
32426 if(this.videourl.length){
32427 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32428 // youtube support only?
32429 cfg.cn[0].cn.cn.push({
32431 cls: 'masonry-brick-image-view',
32434 allowfullscreen : true
32441 initEvents: function()
32443 switch (this.size) {
32476 this.el.on('touchstart', this.onTouchStart, this);
32477 this.el.on('touchmove', this.onTouchMove, this);
32478 this.el.on('touchend', this.onTouchEnd, this);
32479 this.el.on('contextmenu', this.onContextMenu, this);
32481 this.el.on('mouseenter' ,this.enter, this);
32482 this.el.on('mouseleave', this.leave, this);
32483 this.el.on('click', this.onClick, this);
32486 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32487 this.parent().bricks.push(this);
32492 onClick: function(e, el)
32494 var time = this.endTimer - this.startTimer;
32495 // Roo.log(e.preventDefault());
32498 e.preventDefault();
32503 if(!this.preventDefault){
32507 e.preventDefault();
32509 if (this.activcClass != '') {
32510 this.selectBrick();
32513 this.fireEvent('click', this);
32516 enter: function(e, el)
32518 e.preventDefault();
32520 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32524 if(this.bgimage.length && this.html.length){
32525 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32529 leave: function(e, el)
32531 e.preventDefault();
32533 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32537 if(this.bgimage.length && this.html.length){
32538 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32542 onTouchStart: function(e, el)
32544 // e.preventDefault();
32546 this.touchmoved = false;
32548 if(!this.isFitContainer){
32552 if(!this.bgimage.length || !this.html.length){
32556 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32558 this.timer = new Date().getTime();
32562 onTouchMove: function(e, el)
32564 this.touchmoved = true;
32567 onContextMenu : function(e,el)
32569 e.preventDefault();
32570 e.stopPropagation();
32574 onTouchEnd: function(e, el)
32576 // e.preventDefault();
32578 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32585 if(!this.bgimage.length || !this.html.length){
32587 if(this.href.length){
32588 window.location.href = this.href;
32594 if(!this.isFitContainer){
32598 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32600 window.location.href = this.href;
32603 //selection on single brick only
32604 selectBrick : function() {
32606 if (!this.parentId) {
32610 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32611 var index = m.selectedBrick.indexOf(this.id);
32614 m.selectedBrick.splice(index,1);
32615 this.el.removeClass(this.activeClass);
32619 for(var i = 0; i < m.selectedBrick.length; i++) {
32620 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32621 b.el.removeClass(b.activeClass);
32624 m.selectedBrick = [];
32626 m.selectedBrick.push(this.id);
32627 this.el.addClass(this.activeClass);
32633 Roo.apply(Roo.bootstrap.MasonryBrick, {
32636 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32638 * register a Masonry Brick
32639 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32642 register : function(brick)
32644 //this.groups[brick.id] = brick;
32645 this.groups.add(brick.id, brick);
32648 * fetch a masonry brick based on the masonry brick ID
32649 * @param {string} the masonry brick to add
32650 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32653 get: function(brick_id)
32655 // if (typeof(this.groups[brick_id]) == 'undefined') {
32658 // return this.groups[brick_id] ;
32660 if(this.groups.key(brick_id)) {
32661 return this.groups.key(brick_id);
32679 * @class Roo.bootstrap.Brick
32680 * @extends Roo.bootstrap.Component
32681 * Bootstrap Brick class
32684 * Create a new Brick
32685 * @param {Object} config The config object
32688 Roo.bootstrap.Brick = function(config){
32689 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32695 * When a Brick is click
32696 * @param {Roo.bootstrap.Brick} this
32697 * @param {Roo.EventObject} e
32703 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32706 * @cfg {String} title
32710 * @cfg {String} html
32714 * @cfg {String} bgimage
32718 * @cfg {String} cls
32722 * @cfg {String} href
32726 * @cfg {String} video
32730 * @cfg {Boolean} square
32734 getAutoCreate : function()
32736 var cls = 'roo-brick';
32738 if(this.href.length){
32739 cls += ' roo-brick-link';
32742 if(this.bgimage.length){
32743 cls += ' roo-brick-image';
32746 if(!this.html.length && !this.bgimage.length){
32747 cls += ' roo-brick-center-title';
32750 if(!this.html.length && this.bgimage.length){
32751 cls += ' roo-brick-bottom-title';
32755 cls += ' ' + this.cls;
32759 tag: (this.href.length) ? 'a' : 'div',
32764 cls: 'roo-brick-paragraph',
32770 if(this.href.length){
32771 cfg.href = this.href;
32774 var cn = cfg.cn[0].cn;
32776 if(this.title.length){
32779 cls: 'roo-brick-title',
32784 if(this.html.length){
32787 cls: 'roo-brick-text',
32794 if(this.bgimage.length){
32797 cls: 'roo-brick-image-view',
32805 initEvents: function()
32807 if(this.title.length || this.html.length){
32808 this.el.on('mouseenter' ,this.enter, this);
32809 this.el.on('mouseleave', this.leave, this);
32812 Roo.EventManager.onWindowResize(this.resize, this);
32814 if(this.bgimage.length){
32815 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32816 this.imageEl.on('load', this.onImageLoad, this);
32823 onImageLoad : function()
32828 resize : function()
32830 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32832 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32834 if(this.bgimage.length){
32835 var image = this.el.select('.roo-brick-image-view', true).first();
32837 image.setWidth(paragraph.getWidth());
32840 image.setHeight(paragraph.getWidth());
32843 this.el.setHeight(image.getHeight());
32844 paragraph.setHeight(image.getHeight());
32850 enter: function(e, el)
32852 e.preventDefault();
32854 if(this.bgimage.length){
32855 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32856 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32860 leave: function(e, el)
32862 e.preventDefault();
32864 if(this.bgimage.length){
32865 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32866 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32882 * @class Roo.bootstrap.NumberField
32883 * @extends Roo.bootstrap.Input
32884 * Bootstrap NumberField class
32890 * Create a new NumberField
32891 * @param {Object} config The config object
32894 Roo.bootstrap.NumberField = function(config){
32895 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32898 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32901 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32903 allowDecimals : true,
32905 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32907 decimalSeparator : ".",
32909 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32911 decimalPrecision : 2,
32913 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32915 allowNegative : true,
32917 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32919 minValue : Number.NEGATIVE_INFINITY,
32921 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32923 maxValue : Number.MAX_VALUE,
32925 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32927 minText : "The minimum value for this field is {0}",
32929 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32931 maxText : "The maximum value for this field is {0}",
32933 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32934 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32936 nanText : "{0} is not a valid number",
32938 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32943 initEvents : function()
32945 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32947 var allowed = "0123456789";
32949 if(this.allowDecimals){
32950 allowed += this.decimalSeparator;
32953 if(this.allowNegative){
32957 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32959 var keyPress = function(e){
32961 var k = e.getKey();
32963 var c = e.getCharCode();
32966 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32967 allowed.indexOf(String.fromCharCode(c)) === -1
32973 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32977 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32982 this.el.on("keypress", keyPress, this);
32985 validateValue : function(value)
32988 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32992 var num = this.parseValue(value);
32995 this.markInvalid(String.format(this.nanText, value));
32999 if(num < this.minValue){
33000 this.markInvalid(String.format(this.minText, this.minValue));
33004 if(num > this.maxValue){
33005 this.markInvalid(String.format(this.maxText, this.maxValue));
33012 getValue : function()
33014 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
33017 parseValue : function(value)
33019 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33020 return isNaN(value) ? '' : value;
33023 fixPrecision : function(value)
33025 var nan = isNaN(value);
33027 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33028 return nan ? '' : value;
33030 return parseFloat(value).toFixed(this.decimalPrecision);
33033 setValue : function(v)
33035 v = this.fixPrecision(v);
33036 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
33039 decimalPrecisionFcn : function(v)
33041 return Math.floor(v);
33044 beforeBlur : function()
33050 var v = this.parseValue(this.getRawValue());
33065 * @class Roo.bootstrap.DocumentSlider
33066 * @extends Roo.bootstrap.Component
33067 * Bootstrap DocumentSlider class
33070 * Create a new DocumentViewer
33071 * @param {Object} config The config object
33074 Roo.bootstrap.DocumentSlider = function(config){
33075 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33082 * Fire after initEvent
33083 * @param {Roo.bootstrap.DocumentSlider} this
33088 * Fire after update
33089 * @param {Roo.bootstrap.DocumentSlider} this
33095 * @param {Roo.bootstrap.DocumentSlider} this
33101 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33107 getAutoCreate : function()
33111 cls : 'roo-document-slider',
33115 cls : 'roo-document-slider-header',
33119 cls : 'roo-document-slider-header-title'
33125 cls : 'roo-document-slider-body',
33129 cls : 'roo-document-slider-prev',
33133 cls : 'fa fa-chevron-left'
33139 cls : 'roo-document-slider-thumb',
33143 cls : 'roo-document-slider-image'
33149 cls : 'roo-document-slider-next',
33153 cls : 'fa fa-chevron-right'
33165 initEvents : function()
33167 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33168 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33170 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33171 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33173 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33174 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33176 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33177 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33179 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33180 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33182 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33183 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33185 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33186 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33188 this.thumbEl.on('click', this.onClick, this);
33190 this.prevIndicator.on('click', this.prev, this);
33192 this.nextIndicator.on('click', this.next, this);
33196 initial : function()
33198 if(this.files.length){
33199 this.indicator = 1;
33203 this.fireEvent('initial', this);
33206 update : function()
33208 this.imageEl.attr('src', this.files[this.indicator - 1]);
33210 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33212 this.prevIndicator.show();
33214 if(this.indicator == 1){
33215 this.prevIndicator.hide();
33218 this.nextIndicator.show();
33220 if(this.indicator == this.files.length){
33221 this.nextIndicator.hide();
33224 this.thumbEl.scrollTo('top');
33226 this.fireEvent('update', this);
33229 onClick : function(e)
33231 e.preventDefault();
33233 this.fireEvent('click', this);
33238 e.preventDefault();
33240 this.indicator = Math.max(1, this.indicator - 1);
33247 e.preventDefault();
33249 this.indicator = Math.min(this.files.length, this.indicator + 1);
33263 * @class Roo.bootstrap.RadioSet
33264 * @extends Roo.bootstrap.Input
33265 * Bootstrap RadioSet class
33266 * @cfg {String} indicatorpos (left|right) default left
33267 * @cfg {Boolean} inline (true|false) inline the element (default true)
33268 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33270 * Create a new RadioSet
33271 * @param {Object} config The config object
33274 Roo.bootstrap.RadioSet = function(config){
33276 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33280 Roo.bootstrap.RadioSet.register(this);
33285 * Fires when the element is checked or unchecked.
33286 * @param {Roo.bootstrap.RadioSet} this This radio
33287 * @param {Roo.bootstrap.Radio} item The checked item
33294 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33302 indicatorpos : 'left',
33304 getAutoCreate : function()
33308 cls : 'roo-radio-set-label',
33312 html : this.fieldLabel
33317 if(this.indicatorpos == 'left'){
33320 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33321 tooltip : 'This field is required'
33326 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33327 tooltip : 'This field is required'
33333 cls : 'roo-radio-set-items'
33336 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33338 if (align === 'left' && this.fieldLabel.length) {
33341 cls : "roo-radio-set-right",
33347 if(this.labelWidth > 12){
33348 label.style = "width: " + this.labelWidth + 'px';
33351 if(this.labelWidth < 13 && this.labelmd == 0){
33352 this.labelmd = this.labelWidth;
33355 if(this.labellg > 0){
33356 label.cls += ' col-lg-' + this.labellg;
33357 items.cls += ' col-lg-' + (12 - this.labellg);
33360 if(this.labelmd > 0){
33361 label.cls += ' col-md-' + this.labelmd;
33362 items.cls += ' col-md-' + (12 - this.labelmd);
33365 if(this.labelsm > 0){
33366 label.cls += ' col-sm-' + this.labelsm;
33367 items.cls += ' col-sm-' + (12 - this.labelsm);
33370 if(this.labelxs > 0){
33371 label.cls += ' col-xs-' + this.labelxs;
33372 items.cls += ' col-xs-' + (12 - this.labelxs);
33378 cls : 'roo-radio-set',
33382 cls : 'roo-radio-set-input',
33385 value : this.value ? this.value : ''
33392 if(this.weight.length){
33393 cfg.cls += ' roo-radio-' + this.weight;
33397 cfg.cls += ' roo-radio-set-inline';
33401 ['xs','sm','md','lg'].map(function(size){
33402 if (settings[size]) {
33403 cfg.cls += ' col-' + size + '-' + settings[size];
33411 initEvents : function()
33413 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33414 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33416 if(!this.fieldLabel.length){
33417 this.labelEl.hide();
33420 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33421 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33423 this.indicatorEl().addClass('invisible');
33425 this.originalValue = this.getValue();
33429 inputEl: function ()
33431 return this.el.select('.roo-radio-set-input', true).first();
33434 getChildContainer : function()
33436 return this.itemsEl;
33439 register : function(item)
33441 this.radioes.push(item);
33445 validate : function()
33449 Roo.each(this.radioes, function(i){
33458 if(this.allowBlank) {
33462 if(this.disabled || valid){
33467 this.markInvalid();
33472 markValid : function()
33474 if(this.labelEl.isVisible(true)){
33475 this.indicatorEl().removeClass('visible');
33476 this.indicatorEl().addClass('invisible');
33479 this.el.removeClass([this.invalidClass, this.validClass]);
33480 this.el.addClass(this.validClass);
33482 this.fireEvent('valid', this);
33485 markInvalid : function(msg)
33487 if(this.allowBlank || this.disabled){
33491 if(this.labelEl.isVisible(true)){
33492 this.indicatorEl().removeClass('invisible');
33493 this.indicatorEl().addClass('visible');
33496 this.el.removeClass([this.invalidClass, this.validClass]);
33497 this.el.addClass(this.invalidClass);
33499 this.fireEvent('invalid', this, msg);
33503 setValue : function(v, suppressEvent)
33505 if(this.value === v){
33512 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33515 Roo.each(this.radioes, function(i){
33518 i.el.removeClass('checked');
33520 if(i.value === v || i.value.toString() === v.toString()){
33522 i.el.addClass('checked');
33524 if(suppressEvent !== true){
33525 this.fireEvent('check', this, i);
33534 clearInvalid : function(){
33536 if(!this.el || this.preventMark){
33540 this.el.removeClass([this.invalidClass]);
33542 this.fireEvent('valid', this);
33547 Roo.apply(Roo.bootstrap.RadioSet, {
33551 register : function(set)
33553 this.groups[set.name] = set;
33556 get: function(name)
33558 if (typeof(this.groups[name]) == 'undefined') {
33562 return this.groups[name] ;
33568 * Ext JS Library 1.1.1
33569 * Copyright(c) 2006-2007, Ext JS, LLC.
33571 * Originally Released Under LGPL - original licence link has changed is not relivant.
33574 * <script type="text/javascript">
33579 * @class Roo.bootstrap.SplitBar
33580 * @extends Roo.util.Observable
33581 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33585 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33586 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33587 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33588 split.minSize = 100;
33589 split.maxSize = 600;
33590 split.animate = true;
33591 split.on('moved', splitterMoved);
33594 * Create a new SplitBar
33595 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33596 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33597 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33598 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33599 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33600 position of the SplitBar).
33602 Roo.bootstrap.SplitBar = function(cfg){
33607 // dragElement : elm
33608 // resizingElement: el,
33610 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33611 // placement : Roo.bootstrap.SplitBar.LEFT ,
33612 // existingProxy ???
33615 this.el = Roo.get(cfg.dragElement, true);
33616 this.el.dom.unselectable = "on";
33618 this.resizingEl = Roo.get(cfg.resizingElement, true);
33622 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33623 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33626 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33629 * The minimum size of the resizing element. (Defaults to 0)
33635 * The maximum size of the resizing element. (Defaults to 2000)
33638 this.maxSize = 2000;
33641 * Whether to animate the transition to the new size
33644 this.animate = false;
33647 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33650 this.useShim = false;
33655 if(!cfg.existingProxy){
33657 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33659 this.proxy = Roo.get(cfg.existingProxy).dom;
33662 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33665 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33668 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33671 this.dragSpecs = {};
33674 * @private The adapter to use to positon and resize elements
33676 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33677 this.adapter.init(this);
33679 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33681 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33682 this.el.addClass("roo-splitbar-h");
33685 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33686 this.el.addClass("roo-splitbar-v");
33692 * Fires when the splitter is moved (alias for {@link #event-moved})
33693 * @param {Roo.bootstrap.SplitBar} this
33694 * @param {Number} newSize the new width or height
33699 * Fires when the splitter is moved
33700 * @param {Roo.bootstrap.SplitBar} this
33701 * @param {Number} newSize the new width or height
33705 * @event beforeresize
33706 * Fires before the splitter is dragged
33707 * @param {Roo.bootstrap.SplitBar} this
33709 "beforeresize" : true,
33711 "beforeapply" : true
33714 Roo.util.Observable.call(this);
33717 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33718 onStartProxyDrag : function(x, y){
33719 this.fireEvent("beforeresize", this);
33721 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33723 o.enableDisplayMode("block");
33724 // all splitbars share the same overlay
33725 Roo.bootstrap.SplitBar.prototype.overlay = o;
33727 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33728 this.overlay.show();
33729 Roo.get(this.proxy).setDisplayed("block");
33730 var size = this.adapter.getElementSize(this);
33731 this.activeMinSize = this.getMinimumSize();;
33732 this.activeMaxSize = this.getMaximumSize();;
33733 var c1 = size - this.activeMinSize;
33734 var c2 = Math.max(this.activeMaxSize - size, 0);
33735 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33736 this.dd.resetConstraints();
33737 this.dd.setXConstraint(
33738 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33739 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33741 this.dd.setYConstraint(0, 0);
33743 this.dd.resetConstraints();
33744 this.dd.setXConstraint(0, 0);
33745 this.dd.setYConstraint(
33746 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33747 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33750 this.dragSpecs.startSize = size;
33751 this.dragSpecs.startPoint = [x, y];
33752 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33756 * @private Called after the drag operation by the DDProxy
33758 onEndProxyDrag : function(e){
33759 Roo.get(this.proxy).setDisplayed(false);
33760 var endPoint = Roo.lib.Event.getXY(e);
33762 this.overlay.hide();
33765 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33766 newSize = this.dragSpecs.startSize +
33767 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33768 endPoint[0] - this.dragSpecs.startPoint[0] :
33769 this.dragSpecs.startPoint[0] - endPoint[0]
33772 newSize = this.dragSpecs.startSize +
33773 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33774 endPoint[1] - this.dragSpecs.startPoint[1] :
33775 this.dragSpecs.startPoint[1] - endPoint[1]
33778 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33779 if(newSize != this.dragSpecs.startSize){
33780 if(this.fireEvent('beforeapply', this, newSize) !== false){
33781 this.adapter.setElementSize(this, newSize);
33782 this.fireEvent("moved", this, newSize);
33783 this.fireEvent("resize", this, newSize);
33789 * Get the adapter this SplitBar uses
33790 * @return The adapter object
33792 getAdapter : function(){
33793 return this.adapter;
33797 * Set the adapter this SplitBar uses
33798 * @param {Object} adapter A SplitBar adapter object
33800 setAdapter : function(adapter){
33801 this.adapter = adapter;
33802 this.adapter.init(this);
33806 * Gets the minimum size for the resizing element
33807 * @return {Number} The minimum size
33809 getMinimumSize : function(){
33810 return this.minSize;
33814 * Sets the minimum size for the resizing element
33815 * @param {Number} minSize The minimum size
33817 setMinimumSize : function(minSize){
33818 this.minSize = minSize;
33822 * Gets the maximum size for the resizing element
33823 * @return {Number} The maximum size
33825 getMaximumSize : function(){
33826 return this.maxSize;
33830 * Sets the maximum size for the resizing element
33831 * @param {Number} maxSize The maximum size
33833 setMaximumSize : function(maxSize){
33834 this.maxSize = maxSize;
33838 * Sets the initialize size for the resizing element
33839 * @param {Number} size The initial size
33841 setCurrentSize : function(size){
33842 var oldAnimate = this.animate;
33843 this.animate = false;
33844 this.adapter.setElementSize(this, size);
33845 this.animate = oldAnimate;
33849 * Destroy this splitbar.
33850 * @param {Boolean} removeEl True to remove the element
33852 destroy : function(removeEl){
33854 this.shim.remove();
33857 this.proxy.parentNode.removeChild(this.proxy);
33865 * @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.
33867 Roo.bootstrap.SplitBar.createProxy = function(dir){
33868 var proxy = new Roo.Element(document.createElement("div"));
33869 proxy.unselectable();
33870 var cls = 'roo-splitbar-proxy';
33871 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33872 document.body.appendChild(proxy.dom);
33877 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33878 * Default Adapter. It assumes the splitter and resizing element are not positioned
33879 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33881 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33884 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33885 // do nothing for now
33886 init : function(s){
33890 * Called before drag operations to get the current size of the resizing element.
33891 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33893 getElementSize : function(s){
33894 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33895 return s.resizingEl.getWidth();
33897 return s.resizingEl.getHeight();
33902 * Called after drag operations to set the size of the resizing element.
33903 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33904 * @param {Number} newSize The new size to set
33905 * @param {Function} onComplete A function to be invoked when resizing is complete
33907 setElementSize : function(s, newSize, onComplete){
33908 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33910 s.resizingEl.setWidth(newSize);
33912 onComplete(s, newSize);
33915 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33920 s.resizingEl.setHeight(newSize);
33922 onComplete(s, newSize);
33925 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33932 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33933 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33934 * Adapter that moves the splitter element to align with the resized sizing element.
33935 * Used with an absolute positioned SplitBar.
33936 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33937 * document.body, make sure you assign an id to the body element.
33939 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33940 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33941 this.container = Roo.get(container);
33944 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33945 init : function(s){
33946 this.basic.init(s);
33949 getElementSize : function(s){
33950 return this.basic.getElementSize(s);
33953 setElementSize : function(s, newSize, onComplete){
33954 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33957 moveSplitter : function(s){
33958 var yes = Roo.bootstrap.SplitBar;
33959 switch(s.placement){
33961 s.el.setX(s.resizingEl.getRight());
33964 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33967 s.el.setY(s.resizingEl.getBottom());
33970 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33977 * Orientation constant - Create a vertical SplitBar
33981 Roo.bootstrap.SplitBar.VERTICAL = 1;
33984 * Orientation constant - Create a horizontal SplitBar
33988 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33991 * Placement constant - The resizing element is to the left of the splitter element
33995 Roo.bootstrap.SplitBar.LEFT = 1;
33998 * Placement constant - The resizing element is to the right of the splitter element
34002 Roo.bootstrap.SplitBar.RIGHT = 2;
34005 * Placement constant - The resizing element is positioned above the splitter element
34009 Roo.bootstrap.SplitBar.TOP = 3;
34012 * Placement constant - The resizing element is positioned under splitter element
34016 Roo.bootstrap.SplitBar.BOTTOM = 4;
34017 Roo.namespace("Roo.bootstrap.layout");/*
34019 * Ext JS Library 1.1.1
34020 * Copyright(c) 2006-2007, Ext JS, LLC.
34022 * Originally Released Under LGPL - original licence link has changed is not relivant.
34025 * <script type="text/javascript">
34029 * @class Roo.bootstrap.layout.Manager
34030 * @extends Roo.bootstrap.Component
34031 * Base class for layout managers.
34033 Roo.bootstrap.layout.Manager = function(config)
34035 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34041 /** false to disable window resize monitoring @type Boolean */
34042 this.monitorWindowResize = true;
34047 * Fires when a layout is performed.
34048 * @param {Roo.LayoutManager} this
34052 * @event regionresized
34053 * Fires when the user resizes a region.
34054 * @param {Roo.LayoutRegion} region The resized region
34055 * @param {Number} newSize The new size (width for east/west, height for north/south)
34057 "regionresized" : true,
34059 * @event regioncollapsed
34060 * Fires when a region is collapsed.
34061 * @param {Roo.LayoutRegion} region The collapsed region
34063 "regioncollapsed" : true,
34065 * @event regionexpanded
34066 * Fires when a region is expanded.
34067 * @param {Roo.LayoutRegion} region The expanded region
34069 "regionexpanded" : true
34071 this.updating = false;
34074 this.el = Roo.get(config.el);
34080 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34085 monitorWindowResize : true,
34091 onRender : function(ct, position)
34094 this.el = Roo.get(ct);
34097 //this.fireEvent('render',this);
34101 initEvents: function()
34105 // ie scrollbar fix
34106 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34107 document.body.scroll = "no";
34108 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34109 this.el.position('relative');
34111 this.id = this.el.id;
34112 this.el.addClass("roo-layout-container");
34113 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34114 if(this.el.dom != document.body ) {
34115 this.el.on('resize', this.layout,this);
34116 this.el.on('show', this.layout,this);
34122 * Returns true if this layout is currently being updated
34123 * @return {Boolean}
34125 isUpdating : function(){
34126 return this.updating;
34130 * Suspend the LayoutManager from doing auto-layouts while
34131 * making multiple add or remove calls
34133 beginUpdate : function(){
34134 this.updating = true;
34138 * Restore auto-layouts and optionally disable the manager from performing a layout
34139 * @param {Boolean} noLayout true to disable a layout update
34141 endUpdate : function(noLayout){
34142 this.updating = false;
34148 layout: function(){
34152 onRegionResized : function(region, newSize){
34153 this.fireEvent("regionresized", region, newSize);
34157 onRegionCollapsed : function(region){
34158 this.fireEvent("regioncollapsed", region);
34161 onRegionExpanded : function(region){
34162 this.fireEvent("regionexpanded", region);
34166 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34167 * performs box-model adjustments.
34168 * @return {Object} The size as an object {width: (the width), height: (the height)}
34170 getViewSize : function()
34173 if(this.el.dom != document.body){
34174 size = this.el.getSize();
34176 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34178 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34179 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34184 * Returns the Element this layout is bound to.
34185 * @return {Roo.Element}
34187 getEl : function(){
34192 * Returns the specified region.
34193 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34194 * @return {Roo.LayoutRegion}
34196 getRegion : function(target){
34197 return this.regions[target.toLowerCase()];
34200 onWindowResize : function(){
34201 if(this.monitorWindowResize){
34208 * Ext JS Library 1.1.1
34209 * Copyright(c) 2006-2007, Ext JS, LLC.
34211 * Originally Released Under LGPL - original licence link has changed is not relivant.
34214 * <script type="text/javascript">
34217 * @class Roo.bootstrap.layout.Border
34218 * @extends Roo.bootstrap.layout.Manager
34219 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34220 * please see: examples/bootstrap/nested.html<br><br>
34222 <b>The container the layout is rendered into can be either the body element or any other element.
34223 If it is not the body element, the container needs to either be an absolute positioned element,
34224 or you will need to add "position:relative" to the css of the container. You will also need to specify
34225 the container size if it is not the body element.</b>
34228 * Create a new Border
34229 * @param {Object} config Configuration options
34231 Roo.bootstrap.layout.Border = function(config){
34232 config = config || {};
34233 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34237 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34238 if(config[region]){
34239 config[region].region = region;
34240 this.addRegion(config[region]);
34246 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34248 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34250 * Creates and adds a new region if it doesn't already exist.
34251 * @param {String} target The target region key (north, south, east, west or center).
34252 * @param {Object} config The regions config object
34253 * @return {BorderLayoutRegion} The new region
34255 addRegion : function(config)
34257 if(!this.regions[config.region]){
34258 var r = this.factory(config);
34259 this.bindRegion(r);
34261 return this.regions[config.region];
34265 bindRegion : function(r){
34266 this.regions[r.config.region] = r;
34268 r.on("visibilitychange", this.layout, this);
34269 r.on("paneladded", this.layout, this);
34270 r.on("panelremoved", this.layout, this);
34271 r.on("invalidated", this.layout, this);
34272 r.on("resized", this.onRegionResized, this);
34273 r.on("collapsed", this.onRegionCollapsed, this);
34274 r.on("expanded", this.onRegionExpanded, this);
34278 * Performs a layout update.
34280 layout : function()
34282 if(this.updating) {
34286 // render all the rebions if they have not been done alreayd?
34287 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34288 if(this.regions[region] && !this.regions[region].bodyEl){
34289 this.regions[region].onRender(this.el)
34293 var size = this.getViewSize();
34294 var w = size.width;
34295 var h = size.height;
34300 //var x = 0, y = 0;
34302 var rs = this.regions;
34303 var north = rs["north"];
34304 var south = rs["south"];
34305 var west = rs["west"];
34306 var east = rs["east"];
34307 var center = rs["center"];
34308 //if(this.hideOnLayout){ // not supported anymore
34309 //c.el.setStyle("display", "none");
34311 if(north && north.isVisible()){
34312 var b = north.getBox();
34313 var m = north.getMargins();
34314 b.width = w - (m.left+m.right);
34317 centerY = b.height + b.y + m.bottom;
34318 centerH -= centerY;
34319 north.updateBox(this.safeBox(b));
34321 if(south && south.isVisible()){
34322 var b = south.getBox();
34323 var m = south.getMargins();
34324 b.width = w - (m.left+m.right);
34326 var totalHeight = (b.height + m.top + m.bottom);
34327 b.y = h - totalHeight + m.top;
34328 centerH -= totalHeight;
34329 south.updateBox(this.safeBox(b));
34331 if(west && west.isVisible()){
34332 var b = west.getBox();
34333 var m = west.getMargins();
34334 b.height = centerH - (m.top+m.bottom);
34336 b.y = centerY + m.top;
34337 var totalWidth = (b.width + m.left + m.right);
34338 centerX += totalWidth;
34339 centerW -= totalWidth;
34340 west.updateBox(this.safeBox(b));
34342 if(east && east.isVisible()){
34343 var b = east.getBox();
34344 var m = east.getMargins();
34345 b.height = centerH - (m.top+m.bottom);
34346 var totalWidth = (b.width + m.left + m.right);
34347 b.x = w - totalWidth + m.left;
34348 b.y = centerY + m.top;
34349 centerW -= totalWidth;
34350 east.updateBox(this.safeBox(b));
34353 var m = center.getMargins();
34355 x: centerX + m.left,
34356 y: centerY + m.top,
34357 width: centerW - (m.left+m.right),
34358 height: centerH - (m.top+m.bottom)
34360 //if(this.hideOnLayout){
34361 //center.el.setStyle("display", "block");
34363 center.updateBox(this.safeBox(centerBox));
34366 this.fireEvent("layout", this);
34370 safeBox : function(box){
34371 box.width = Math.max(0, box.width);
34372 box.height = Math.max(0, box.height);
34377 * Adds a ContentPanel (or subclass) to this layout.
34378 * @param {String} target The target region key (north, south, east, west or center).
34379 * @param {Roo.ContentPanel} panel The panel to add
34380 * @return {Roo.ContentPanel} The added panel
34382 add : function(target, panel){
34384 target = target.toLowerCase();
34385 return this.regions[target].add(panel);
34389 * Remove a ContentPanel (or subclass) to this layout.
34390 * @param {String} target The target region key (north, south, east, west or center).
34391 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34392 * @return {Roo.ContentPanel} The removed panel
34394 remove : function(target, panel){
34395 target = target.toLowerCase();
34396 return this.regions[target].remove(panel);
34400 * Searches all regions for a panel with the specified id
34401 * @param {String} panelId
34402 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34404 findPanel : function(panelId){
34405 var rs = this.regions;
34406 for(var target in rs){
34407 if(typeof rs[target] != "function"){
34408 var p = rs[target].getPanel(panelId);
34418 * Searches all regions for a panel with the specified id and activates (shows) it.
34419 * @param {String/ContentPanel} panelId The panels id or the panel itself
34420 * @return {Roo.ContentPanel} The shown panel or null
34422 showPanel : function(panelId) {
34423 var rs = this.regions;
34424 for(var target in rs){
34425 var r = rs[target];
34426 if(typeof r != "function"){
34427 if(r.hasPanel(panelId)){
34428 return r.showPanel(panelId);
34436 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34437 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34440 restoreState : function(provider){
34442 provider = Roo.state.Manager;
34444 var sm = new Roo.LayoutStateManager();
34445 sm.init(this, provider);
34451 * Adds a xtype elements to the layout.
34455 xtype : 'ContentPanel',
34462 xtype : 'NestedLayoutPanel',
34468 items : [ ... list of content panels or nested layout panels.. ]
34472 * @param {Object} cfg Xtype definition of item to add.
34474 addxtype : function(cfg)
34476 // basically accepts a pannel...
34477 // can accept a layout region..!?!?
34478 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34481 // theory? children can only be panels??
34483 //if (!cfg.xtype.match(/Panel$/)) {
34488 if (typeof(cfg.region) == 'undefined') {
34489 Roo.log("Failed to add Panel, region was not set");
34493 var region = cfg.region;
34499 xitems = cfg.items;
34506 case 'Content': // ContentPanel (el, cfg)
34507 case 'Scroll': // ContentPanel (el, cfg)
34509 cfg.autoCreate = true;
34510 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34512 // var el = this.el.createChild();
34513 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34516 this.add(region, ret);
34520 case 'TreePanel': // our new panel!
34521 cfg.el = this.el.createChild();
34522 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34523 this.add(region, ret);
34528 // create a new Layout (which is a Border Layout...
34530 var clayout = cfg.layout;
34531 clayout.el = this.el.createChild();
34532 clayout.items = clayout.items || [];
34536 // replace this exitems with the clayout ones..
34537 xitems = clayout.items;
34539 // force background off if it's in center...
34540 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34541 cfg.background = false;
34543 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34546 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34547 //console.log('adding nested layout panel ' + cfg.toSource());
34548 this.add(region, ret);
34549 nb = {}; /// find first...
34554 // needs grid and region
34556 //var el = this.getRegion(region).el.createChild();
34558 *var el = this.el.createChild();
34559 // create the grid first...
34560 cfg.grid.container = el;
34561 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34564 if (region == 'center' && this.active ) {
34565 cfg.background = false;
34568 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34570 this.add(region, ret);
34572 if (cfg.background) {
34573 // render grid on panel activation (if panel background)
34574 ret.on('activate', function(gp) {
34575 if (!gp.grid.rendered) {
34576 // gp.grid.render(el);
34580 // cfg.grid.render(el);
34586 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34587 // it was the old xcomponent building that caused this before.
34588 // espeically if border is the top element in the tree.
34598 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34600 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34601 this.add(region, ret);
34605 throw "Can not add '" + cfg.xtype + "' to Border";
34611 this.beginUpdate();
34615 Roo.each(xitems, function(i) {
34616 region = nb && i.region ? i.region : false;
34618 var add = ret.addxtype(i);
34621 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34622 if (!i.background) {
34623 abn[region] = nb[region] ;
34630 // make the last non-background panel active..
34631 //if (nb) { Roo.log(abn); }
34634 for(var r in abn) {
34635 region = this.getRegion(r);
34637 // tried using nb[r], but it does not work..
34639 region.showPanel(abn[r]);
34650 factory : function(cfg)
34653 var validRegions = Roo.bootstrap.layout.Border.regions;
34655 var target = cfg.region;
34658 var r = Roo.bootstrap.layout;
34662 return new r.North(cfg);
34664 return new r.South(cfg);
34666 return new r.East(cfg);
34668 return new r.West(cfg);
34670 return new r.Center(cfg);
34672 throw 'Layout region "'+target+'" not supported.';
34679 * Ext JS Library 1.1.1
34680 * Copyright(c) 2006-2007, Ext JS, LLC.
34682 * Originally Released Under LGPL - original licence link has changed is not relivant.
34685 * <script type="text/javascript">
34689 * @class Roo.bootstrap.layout.Basic
34690 * @extends Roo.util.Observable
34691 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34692 * and does not have a titlebar, tabs or any other features. All it does is size and position
34693 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34694 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34695 * @cfg {string} region the region that it inhabits..
34696 * @cfg {bool} skipConfig skip config?
34700 Roo.bootstrap.layout.Basic = function(config){
34702 this.mgr = config.mgr;
34704 this.position = config.region;
34706 var skipConfig = config.skipConfig;
34710 * @scope Roo.BasicLayoutRegion
34714 * @event beforeremove
34715 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34716 * @param {Roo.LayoutRegion} this
34717 * @param {Roo.ContentPanel} panel The panel
34718 * @param {Object} e The cancel event object
34720 "beforeremove" : true,
34722 * @event invalidated
34723 * Fires when the layout for this region is changed.
34724 * @param {Roo.LayoutRegion} this
34726 "invalidated" : true,
34728 * @event visibilitychange
34729 * Fires when this region is shown or hidden
34730 * @param {Roo.LayoutRegion} this
34731 * @param {Boolean} visibility true or false
34733 "visibilitychange" : true,
34735 * @event paneladded
34736 * Fires when a panel is added.
34737 * @param {Roo.LayoutRegion} this
34738 * @param {Roo.ContentPanel} panel The panel
34740 "paneladded" : true,
34742 * @event panelremoved
34743 * Fires when a panel is removed.
34744 * @param {Roo.LayoutRegion} this
34745 * @param {Roo.ContentPanel} panel The panel
34747 "panelremoved" : true,
34749 * @event beforecollapse
34750 * Fires when this region before collapse.
34751 * @param {Roo.LayoutRegion} this
34753 "beforecollapse" : true,
34756 * Fires when this region is collapsed.
34757 * @param {Roo.LayoutRegion} this
34759 "collapsed" : true,
34762 * Fires when this region is expanded.
34763 * @param {Roo.LayoutRegion} this
34768 * Fires when this region is slid into view.
34769 * @param {Roo.LayoutRegion} this
34771 "slideshow" : true,
34774 * Fires when this region slides out of view.
34775 * @param {Roo.LayoutRegion} this
34777 "slidehide" : true,
34779 * @event panelactivated
34780 * Fires when a panel is activated.
34781 * @param {Roo.LayoutRegion} this
34782 * @param {Roo.ContentPanel} panel The activated panel
34784 "panelactivated" : true,
34787 * Fires when the user resizes this region.
34788 * @param {Roo.LayoutRegion} this
34789 * @param {Number} newSize The new size (width for east/west, height for north/south)
34793 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34794 this.panels = new Roo.util.MixedCollection();
34795 this.panels.getKey = this.getPanelId.createDelegate(this);
34797 this.activePanel = null;
34798 // ensure listeners are added...
34800 if (config.listeners || config.events) {
34801 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34802 listeners : config.listeners || {},
34803 events : config.events || {}
34807 if(skipConfig !== true){
34808 this.applyConfig(config);
34812 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34814 getPanelId : function(p){
34818 applyConfig : function(config){
34819 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34820 this.config = config;
34825 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34826 * the width, for horizontal (north, south) the height.
34827 * @param {Number} newSize The new width or height
34829 resizeTo : function(newSize){
34830 var el = this.el ? this.el :
34831 (this.activePanel ? this.activePanel.getEl() : null);
34833 switch(this.position){
34836 el.setWidth(newSize);
34837 this.fireEvent("resized", this, newSize);
34841 el.setHeight(newSize);
34842 this.fireEvent("resized", this, newSize);
34848 getBox : function(){
34849 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34852 getMargins : function(){
34853 return this.margins;
34856 updateBox : function(box){
34858 var el = this.activePanel.getEl();
34859 el.dom.style.left = box.x + "px";
34860 el.dom.style.top = box.y + "px";
34861 this.activePanel.setSize(box.width, box.height);
34865 * Returns the container element for this region.
34866 * @return {Roo.Element}
34868 getEl : function(){
34869 return this.activePanel;
34873 * Returns true if this region is currently visible.
34874 * @return {Boolean}
34876 isVisible : function(){
34877 return this.activePanel ? true : false;
34880 setActivePanel : function(panel){
34881 panel = this.getPanel(panel);
34882 if(this.activePanel && this.activePanel != panel){
34883 this.activePanel.setActiveState(false);
34884 this.activePanel.getEl().setLeftTop(-10000,-10000);
34886 this.activePanel = panel;
34887 panel.setActiveState(true);
34889 panel.setSize(this.box.width, this.box.height);
34891 this.fireEvent("panelactivated", this, panel);
34892 this.fireEvent("invalidated");
34896 * Show the specified panel.
34897 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34898 * @return {Roo.ContentPanel} The shown panel or null
34900 showPanel : function(panel){
34901 panel = this.getPanel(panel);
34903 this.setActivePanel(panel);
34909 * Get the active panel for this region.
34910 * @return {Roo.ContentPanel} The active panel or null
34912 getActivePanel : function(){
34913 return this.activePanel;
34917 * Add the passed ContentPanel(s)
34918 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34919 * @return {Roo.ContentPanel} The panel added (if only one was added)
34921 add : function(panel){
34922 if(arguments.length > 1){
34923 for(var i = 0, len = arguments.length; i < len; i++) {
34924 this.add(arguments[i]);
34928 if(this.hasPanel(panel)){
34929 this.showPanel(panel);
34932 var el = panel.getEl();
34933 if(el.dom.parentNode != this.mgr.el.dom){
34934 this.mgr.el.dom.appendChild(el.dom);
34936 if(panel.setRegion){
34937 panel.setRegion(this);
34939 this.panels.add(panel);
34940 el.setStyle("position", "absolute");
34941 if(!panel.background){
34942 this.setActivePanel(panel);
34943 if(this.config.initialSize && this.panels.getCount()==1){
34944 this.resizeTo(this.config.initialSize);
34947 this.fireEvent("paneladded", this, panel);
34952 * Returns true if the panel is in this region.
34953 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34954 * @return {Boolean}
34956 hasPanel : function(panel){
34957 if(typeof panel == "object"){ // must be panel obj
34958 panel = panel.getId();
34960 return this.getPanel(panel) ? true : false;
34964 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34965 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34966 * @param {Boolean} preservePanel Overrides the config preservePanel option
34967 * @return {Roo.ContentPanel} The panel that was removed
34969 remove : function(panel, preservePanel){
34970 panel = this.getPanel(panel);
34975 this.fireEvent("beforeremove", this, panel, e);
34976 if(e.cancel === true){
34979 var panelId = panel.getId();
34980 this.panels.removeKey(panelId);
34985 * Returns the panel specified or null if it's not in this region.
34986 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34987 * @return {Roo.ContentPanel}
34989 getPanel : function(id){
34990 if(typeof id == "object"){ // must be panel obj
34993 return this.panels.get(id);
34997 * Returns this regions position (north/south/east/west/center).
35000 getPosition: function(){
35001 return this.position;
35005 * Ext JS Library 1.1.1
35006 * Copyright(c) 2006-2007, Ext JS, LLC.
35008 * Originally Released Under LGPL - original licence link has changed is not relivant.
35011 * <script type="text/javascript">
35015 * @class Roo.bootstrap.layout.Region
35016 * @extends Roo.bootstrap.layout.Basic
35017 * This class represents a region in a layout manager.
35019 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35020 * @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})
35021 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35022 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35023 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35024 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35025 * @cfg {String} title The title for the region (overrides panel titles)
35026 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35027 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35028 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35029 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35030 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35031 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35032 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35033 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35034 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35035 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35037 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35038 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35039 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35040 * @cfg {Number} width For East/West panels
35041 * @cfg {Number} height For North/South panels
35042 * @cfg {Boolean} split To show the splitter
35043 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35045 * @cfg {string} cls Extra CSS classes to add to region
35047 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35048 * @cfg {string} region the region that it inhabits..
35051 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35052 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35054 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35055 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35056 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35058 Roo.bootstrap.layout.Region = function(config)
35060 this.applyConfig(config);
35062 var mgr = config.mgr;
35063 var pos = config.region;
35064 config.skipConfig = true;
35065 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35068 this.onRender(mgr.el);
35071 this.visible = true;
35072 this.collapsed = false;
35073 this.unrendered_panels = [];
35076 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35078 position: '', // set by wrapper (eg. north/south etc..)
35079 unrendered_panels : null, // unrendered panels.
35080 createBody : function(){
35081 /** This region's body element
35082 * @type Roo.Element */
35083 this.bodyEl = this.el.createChild({
35085 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35089 onRender: function(ctr, pos)
35091 var dh = Roo.DomHelper;
35092 /** This region's container element
35093 * @type Roo.Element */
35094 this.el = dh.append(ctr.dom, {
35096 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35098 /** This region's title element
35099 * @type Roo.Element */
35101 this.titleEl = dh.append(this.el.dom,
35104 unselectable: "on",
35105 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35107 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35108 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35111 this.titleEl.enableDisplayMode();
35112 /** This region's title text element
35113 * @type HTMLElement */
35114 this.titleTextEl = this.titleEl.dom.firstChild;
35115 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35117 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35118 this.closeBtn.enableDisplayMode();
35119 this.closeBtn.on("click", this.closeClicked, this);
35120 this.closeBtn.hide();
35122 this.createBody(this.config);
35123 if(this.config.hideWhenEmpty){
35125 this.on("paneladded", this.validateVisibility, this);
35126 this.on("panelremoved", this.validateVisibility, this);
35128 if(this.autoScroll){
35129 this.bodyEl.setStyle("overflow", "auto");
35131 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35133 //if(c.titlebar !== false){
35134 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35135 this.titleEl.hide();
35137 this.titleEl.show();
35138 if(this.config.title){
35139 this.titleTextEl.innerHTML = this.config.title;
35143 if(this.config.collapsed){
35144 this.collapse(true);
35146 if(this.config.hidden){
35150 if (this.unrendered_panels && this.unrendered_panels.length) {
35151 for (var i =0;i< this.unrendered_panels.length; i++) {
35152 this.add(this.unrendered_panels[i]);
35154 this.unrendered_panels = null;
35160 applyConfig : function(c)
35163 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35164 var dh = Roo.DomHelper;
35165 if(c.titlebar !== false){
35166 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35167 this.collapseBtn.on("click", this.collapse, this);
35168 this.collapseBtn.enableDisplayMode();
35170 if(c.showPin === true || this.showPin){
35171 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35172 this.stickBtn.enableDisplayMode();
35173 this.stickBtn.on("click", this.expand, this);
35174 this.stickBtn.hide();
35179 /** This region's collapsed element
35180 * @type Roo.Element */
35183 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35184 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35187 if(c.floatable !== false){
35188 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35189 this.collapsedEl.on("click", this.collapseClick, this);
35192 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35193 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35194 id: "message", unselectable: "on", style:{"float":"left"}});
35195 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35197 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35198 this.expandBtn.on("click", this.expand, this);
35202 if(this.collapseBtn){
35203 this.collapseBtn.setVisible(c.collapsible == true);
35206 this.cmargins = c.cmargins || this.cmargins ||
35207 (this.position == "west" || this.position == "east" ?
35208 {top: 0, left: 2, right:2, bottom: 0} :
35209 {top: 2, left: 0, right:0, bottom: 2});
35211 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35214 this.bottomTabs = c.tabPosition != "top";
35216 this.autoScroll = c.autoScroll || false;
35221 this.duration = c.duration || .30;
35222 this.slideDuration = c.slideDuration || .45;
35227 * Returns true if this region is currently visible.
35228 * @return {Boolean}
35230 isVisible : function(){
35231 return this.visible;
35235 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35236 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35238 //setCollapsedTitle : function(title){
35239 // title = title || " ";
35240 // if(this.collapsedTitleTextEl){
35241 // this.collapsedTitleTextEl.innerHTML = title;
35245 getBox : function(){
35247 // if(!this.collapsed){
35248 b = this.el.getBox(false, true);
35250 // b = this.collapsedEl.getBox(false, true);
35255 getMargins : function(){
35256 return this.margins;
35257 //return this.collapsed ? this.cmargins : this.margins;
35260 highlight : function(){
35261 this.el.addClass("x-layout-panel-dragover");
35264 unhighlight : function(){
35265 this.el.removeClass("x-layout-panel-dragover");
35268 updateBox : function(box)
35270 if (!this.bodyEl) {
35271 return; // not rendered yet..
35275 if(!this.collapsed){
35276 this.el.dom.style.left = box.x + "px";
35277 this.el.dom.style.top = box.y + "px";
35278 this.updateBody(box.width, box.height);
35280 this.collapsedEl.dom.style.left = box.x + "px";
35281 this.collapsedEl.dom.style.top = box.y + "px";
35282 this.collapsedEl.setSize(box.width, box.height);
35285 this.tabs.autoSizeTabs();
35289 updateBody : function(w, h)
35292 this.el.setWidth(w);
35293 w -= this.el.getBorderWidth("rl");
35294 if(this.config.adjustments){
35295 w += this.config.adjustments[0];
35298 if(h !== null && h > 0){
35299 this.el.setHeight(h);
35300 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35301 h -= this.el.getBorderWidth("tb");
35302 if(this.config.adjustments){
35303 h += this.config.adjustments[1];
35305 this.bodyEl.setHeight(h);
35307 h = this.tabs.syncHeight(h);
35310 if(this.panelSize){
35311 w = w !== null ? w : this.panelSize.width;
35312 h = h !== null ? h : this.panelSize.height;
35314 if(this.activePanel){
35315 var el = this.activePanel.getEl();
35316 w = w !== null ? w : el.getWidth();
35317 h = h !== null ? h : el.getHeight();
35318 this.panelSize = {width: w, height: h};
35319 this.activePanel.setSize(w, h);
35321 if(Roo.isIE && this.tabs){
35322 this.tabs.el.repaint();
35327 * Returns the container element for this region.
35328 * @return {Roo.Element}
35330 getEl : function(){
35335 * Hides this region.
35338 //if(!this.collapsed){
35339 this.el.dom.style.left = "-2000px";
35342 // this.collapsedEl.dom.style.left = "-2000px";
35343 // this.collapsedEl.hide();
35345 this.visible = false;
35346 this.fireEvent("visibilitychange", this, false);
35350 * Shows this region if it was previously hidden.
35353 //if(!this.collapsed){
35356 // this.collapsedEl.show();
35358 this.visible = true;
35359 this.fireEvent("visibilitychange", this, true);
35362 closeClicked : function(){
35363 if(this.activePanel){
35364 this.remove(this.activePanel);
35368 collapseClick : function(e){
35370 e.stopPropagation();
35373 e.stopPropagation();
35379 * Collapses this region.
35380 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35383 collapse : function(skipAnim, skipCheck = false){
35384 if(this.collapsed) {
35388 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35390 this.collapsed = true;
35392 this.split.el.hide();
35394 if(this.config.animate && skipAnim !== true){
35395 this.fireEvent("invalidated", this);
35396 this.animateCollapse();
35398 this.el.setLocation(-20000,-20000);
35400 this.collapsedEl.show();
35401 this.fireEvent("collapsed", this);
35402 this.fireEvent("invalidated", this);
35408 animateCollapse : function(){
35413 * Expands this region if it was previously collapsed.
35414 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35415 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35418 expand : function(e, skipAnim){
35420 e.stopPropagation();
35422 if(!this.collapsed || this.el.hasActiveFx()) {
35426 this.afterSlideIn();
35429 this.collapsed = false;
35430 if(this.config.animate && skipAnim !== true){
35431 this.animateExpand();
35435 this.split.el.show();
35437 this.collapsedEl.setLocation(-2000,-2000);
35438 this.collapsedEl.hide();
35439 this.fireEvent("invalidated", this);
35440 this.fireEvent("expanded", this);
35444 animateExpand : function(){
35448 initTabs : function()
35450 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35452 var ts = new Roo.bootstrap.panel.Tabs({
35453 el: this.bodyEl.dom,
35454 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35455 disableTooltips: this.config.disableTabTips,
35456 toolbar : this.config.toolbar
35459 if(this.config.hideTabs){
35460 ts.stripWrap.setDisplayed(false);
35463 ts.resizeTabs = this.config.resizeTabs === true;
35464 ts.minTabWidth = this.config.minTabWidth || 40;
35465 ts.maxTabWidth = this.config.maxTabWidth || 250;
35466 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35467 ts.monitorResize = false;
35468 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35469 ts.bodyEl.addClass('roo-layout-tabs-body');
35470 this.panels.each(this.initPanelAsTab, this);
35473 initPanelAsTab : function(panel){
35474 var ti = this.tabs.addTab(
35478 this.config.closeOnTab && panel.isClosable(),
35481 if(panel.tabTip !== undefined){
35482 ti.setTooltip(panel.tabTip);
35484 ti.on("activate", function(){
35485 this.setActivePanel(panel);
35488 if(this.config.closeOnTab){
35489 ti.on("beforeclose", function(t, e){
35491 this.remove(panel);
35495 panel.tabItem = ti;
35500 updatePanelTitle : function(panel, title)
35502 if(this.activePanel == panel){
35503 this.updateTitle(title);
35506 var ti = this.tabs.getTab(panel.getEl().id);
35508 if(panel.tabTip !== undefined){
35509 ti.setTooltip(panel.tabTip);
35514 updateTitle : function(title){
35515 if(this.titleTextEl && !this.config.title){
35516 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35520 setActivePanel : function(panel)
35522 panel = this.getPanel(panel);
35523 if(this.activePanel && this.activePanel != panel){
35524 if(this.activePanel.setActiveState(false) === false){
35528 this.activePanel = panel;
35529 panel.setActiveState(true);
35530 if(this.panelSize){
35531 panel.setSize(this.panelSize.width, this.panelSize.height);
35534 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35536 this.updateTitle(panel.getTitle());
35538 this.fireEvent("invalidated", this);
35540 this.fireEvent("panelactivated", this, panel);
35544 * Shows the specified panel.
35545 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35546 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35548 showPanel : function(panel)
35550 panel = this.getPanel(panel);
35553 var tab = this.tabs.getTab(panel.getEl().id);
35554 if(tab.isHidden()){
35555 this.tabs.unhideTab(tab.id);
35559 this.setActivePanel(panel);
35566 * Get the active panel for this region.
35567 * @return {Roo.ContentPanel} The active panel or null
35569 getActivePanel : function(){
35570 return this.activePanel;
35573 validateVisibility : function(){
35574 if(this.panels.getCount() < 1){
35575 this.updateTitle(" ");
35576 this.closeBtn.hide();
35579 if(!this.isVisible()){
35586 * Adds the passed ContentPanel(s) to this region.
35587 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35588 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35590 add : function(panel)
35592 if(arguments.length > 1){
35593 for(var i = 0, len = arguments.length; i < len; i++) {
35594 this.add(arguments[i]);
35599 // if we have not been rendered yet, then we can not really do much of this..
35600 if (!this.bodyEl) {
35601 this.unrendered_panels.push(panel);
35608 if(this.hasPanel(panel)){
35609 this.showPanel(panel);
35612 panel.setRegion(this);
35613 this.panels.add(panel);
35614 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35615 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35616 // and hide them... ???
35617 this.bodyEl.dom.appendChild(panel.getEl().dom);
35618 if(panel.background !== true){
35619 this.setActivePanel(panel);
35621 this.fireEvent("paneladded", this, panel);
35628 this.initPanelAsTab(panel);
35632 if(panel.background !== true){
35633 this.tabs.activate(panel.getEl().id);
35635 this.fireEvent("paneladded", this, panel);
35640 * Hides the tab for the specified panel.
35641 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35643 hidePanel : function(panel){
35644 if(this.tabs && (panel = this.getPanel(panel))){
35645 this.tabs.hideTab(panel.getEl().id);
35650 * Unhides the tab for a previously hidden panel.
35651 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35653 unhidePanel : function(panel){
35654 if(this.tabs && (panel = this.getPanel(panel))){
35655 this.tabs.unhideTab(panel.getEl().id);
35659 clearPanels : function(){
35660 while(this.panels.getCount() > 0){
35661 this.remove(this.panels.first());
35666 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35667 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35668 * @param {Boolean} preservePanel Overrides the config preservePanel option
35669 * @return {Roo.ContentPanel} The panel that was removed
35671 remove : function(panel, preservePanel)
35673 panel = this.getPanel(panel);
35678 this.fireEvent("beforeremove", this, panel, e);
35679 if(e.cancel === true){
35682 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35683 var panelId = panel.getId();
35684 this.panels.removeKey(panelId);
35686 document.body.appendChild(panel.getEl().dom);
35689 this.tabs.removeTab(panel.getEl().id);
35690 }else if (!preservePanel){
35691 this.bodyEl.dom.removeChild(panel.getEl().dom);
35693 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35694 var p = this.panels.first();
35695 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35696 tempEl.appendChild(p.getEl().dom);
35697 this.bodyEl.update("");
35698 this.bodyEl.dom.appendChild(p.getEl().dom);
35700 this.updateTitle(p.getTitle());
35702 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35703 this.setActivePanel(p);
35705 panel.setRegion(null);
35706 if(this.activePanel == panel){
35707 this.activePanel = null;
35709 if(this.config.autoDestroy !== false && preservePanel !== true){
35710 try{panel.destroy();}catch(e){}
35712 this.fireEvent("panelremoved", this, panel);
35717 * Returns the TabPanel component used by this region
35718 * @return {Roo.TabPanel}
35720 getTabs : function(){
35724 createTool : function(parentEl, className){
35725 var btn = Roo.DomHelper.append(parentEl, {
35727 cls: "x-layout-tools-button",
35730 cls: "roo-layout-tools-button-inner " + className,
35734 btn.addClassOnOver("roo-layout-tools-button-over");
35739 * Ext JS Library 1.1.1
35740 * Copyright(c) 2006-2007, Ext JS, LLC.
35742 * Originally Released Under LGPL - original licence link has changed is not relivant.
35745 * <script type="text/javascript">
35751 * @class Roo.SplitLayoutRegion
35752 * @extends Roo.LayoutRegion
35753 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35755 Roo.bootstrap.layout.Split = function(config){
35756 this.cursor = config.cursor;
35757 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35760 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35762 splitTip : "Drag to resize.",
35763 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35764 useSplitTips : false,
35766 applyConfig : function(config){
35767 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35770 onRender : function(ctr,pos) {
35772 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35773 if(!this.config.split){
35778 var splitEl = Roo.DomHelper.append(ctr.dom, {
35780 id: this.el.id + "-split",
35781 cls: "roo-layout-split roo-layout-split-"+this.position,
35784 /** The SplitBar for this region
35785 * @type Roo.SplitBar */
35786 // does not exist yet...
35787 Roo.log([this.position, this.orientation]);
35789 this.split = new Roo.bootstrap.SplitBar({
35790 dragElement : splitEl,
35791 resizingElement: this.el,
35792 orientation : this.orientation
35795 this.split.on("moved", this.onSplitMove, this);
35796 this.split.useShim = this.config.useShim === true;
35797 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35798 if(this.useSplitTips){
35799 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35801 //if(config.collapsible){
35802 // this.split.el.on("dblclick", this.collapse, this);
35805 if(typeof this.config.minSize != "undefined"){
35806 this.split.minSize = this.config.minSize;
35808 if(typeof this.config.maxSize != "undefined"){
35809 this.split.maxSize = this.config.maxSize;
35811 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35812 this.hideSplitter();
35817 getHMaxSize : function(){
35818 var cmax = this.config.maxSize || 10000;
35819 var center = this.mgr.getRegion("center");
35820 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35823 getVMaxSize : function(){
35824 var cmax = this.config.maxSize || 10000;
35825 var center = this.mgr.getRegion("center");
35826 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35829 onSplitMove : function(split, newSize){
35830 this.fireEvent("resized", this, newSize);
35834 * Returns the {@link Roo.SplitBar} for this region.
35835 * @return {Roo.SplitBar}
35837 getSplitBar : function(){
35842 this.hideSplitter();
35843 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35846 hideSplitter : function(){
35848 this.split.el.setLocation(-2000,-2000);
35849 this.split.el.hide();
35855 this.split.el.show();
35857 Roo.bootstrap.layout.Split.superclass.show.call(this);
35860 beforeSlide: function(){
35861 if(Roo.isGecko){// firefox overflow auto bug workaround
35862 this.bodyEl.clip();
35864 this.tabs.bodyEl.clip();
35866 if(this.activePanel){
35867 this.activePanel.getEl().clip();
35869 if(this.activePanel.beforeSlide){
35870 this.activePanel.beforeSlide();
35876 afterSlide : function(){
35877 if(Roo.isGecko){// firefox overflow auto bug workaround
35878 this.bodyEl.unclip();
35880 this.tabs.bodyEl.unclip();
35882 if(this.activePanel){
35883 this.activePanel.getEl().unclip();
35884 if(this.activePanel.afterSlide){
35885 this.activePanel.afterSlide();
35891 initAutoHide : function(){
35892 if(this.autoHide !== false){
35893 if(!this.autoHideHd){
35894 var st = new Roo.util.DelayedTask(this.slideIn, this);
35895 this.autoHideHd = {
35896 "mouseout": function(e){
35897 if(!e.within(this.el, true)){
35901 "mouseover" : function(e){
35907 this.el.on(this.autoHideHd);
35911 clearAutoHide : function(){
35912 if(this.autoHide !== false){
35913 this.el.un("mouseout", this.autoHideHd.mouseout);
35914 this.el.un("mouseover", this.autoHideHd.mouseover);
35918 clearMonitor : function(){
35919 Roo.get(document).un("click", this.slideInIf, this);
35922 // these names are backwards but not changed for compat
35923 slideOut : function(){
35924 if(this.isSlid || this.el.hasActiveFx()){
35927 this.isSlid = true;
35928 if(this.collapseBtn){
35929 this.collapseBtn.hide();
35931 this.closeBtnState = this.closeBtn.getStyle('display');
35932 this.closeBtn.hide();
35934 this.stickBtn.show();
35937 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35938 this.beforeSlide();
35939 this.el.setStyle("z-index", 10001);
35940 this.el.slideIn(this.getSlideAnchor(), {
35941 callback: function(){
35943 this.initAutoHide();
35944 Roo.get(document).on("click", this.slideInIf, this);
35945 this.fireEvent("slideshow", this);
35952 afterSlideIn : function(){
35953 this.clearAutoHide();
35954 this.isSlid = false;
35955 this.clearMonitor();
35956 this.el.setStyle("z-index", "");
35957 if(this.collapseBtn){
35958 this.collapseBtn.show();
35960 this.closeBtn.setStyle('display', this.closeBtnState);
35962 this.stickBtn.hide();
35964 this.fireEvent("slidehide", this);
35967 slideIn : function(cb){
35968 if(!this.isSlid || this.el.hasActiveFx()){
35972 this.isSlid = false;
35973 this.beforeSlide();
35974 this.el.slideOut(this.getSlideAnchor(), {
35975 callback: function(){
35976 this.el.setLeftTop(-10000, -10000);
35978 this.afterSlideIn();
35986 slideInIf : function(e){
35987 if(!e.within(this.el)){
35992 animateCollapse : function(){
35993 this.beforeSlide();
35994 this.el.setStyle("z-index", 20000);
35995 var anchor = this.getSlideAnchor();
35996 this.el.slideOut(anchor, {
35997 callback : function(){
35998 this.el.setStyle("z-index", "");
35999 this.collapsedEl.slideIn(anchor, {duration:.3});
36001 this.el.setLocation(-10000,-10000);
36003 this.fireEvent("collapsed", this);
36010 animateExpand : function(){
36011 this.beforeSlide();
36012 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36013 this.el.setStyle("z-index", 20000);
36014 this.collapsedEl.hide({
36017 this.el.slideIn(this.getSlideAnchor(), {
36018 callback : function(){
36019 this.el.setStyle("z-index", "");
36022 this.split.el.show();
36024 this.fireEvent("invalidated", this);
36025 this.fireEvent("expanded", this);
36053 getAnchor : function(){
36054 return this.anchors[this.position];
36057 getCollapseAnchor : function(){
36058 return this.canchors[this.position];
36061 getSlideAnchor : function(){
36062 return this.sanchors[this.position];
36065 getAlignAdj : function(){
36066 var cm = this.cmargins;
36067 switch(this.position){
36083 getExpandAdj : function(){
36084 var c = this.collapsedEl, cm = this.cmargins;
36085 switch(this.position){
36087 return [-(cm.right+c.getWidth()+cm.left), 0];
36090 return [cm.right+c.getWidth()+cm.left, 0];
36093 return [0, -(cm.top+cm.bottom+c.getHeight())];
36096 return [0, cm.top+cm.bottom+c.getHeight()];
36102 * Ext JS Library 1.1.1
36103 * Copyright(c) 2006-2007, Ext JS, LLC.
36105 * Originally Released Under LGPL - original licence link has changed is not relivant.
36108 * <script type="text/javascript">
36111 * These classes are private internal classes
36113 Roo.bootstrap.layout.Center = function(config){
36114 config.region = "center";
36115 Roo.bootstrap.layout.Region.call(this, config);
36116 this.visible = true;
36117 this.minWidth = config.minWidth || 20;
36118 this.minHeight = config.minHeight || 20;
36121 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36123 // center panel can't be hidden
36127 // center panel can't be hidden
36130 getMinWidth: function(){
36131 return this.minWidth;
36134 getMinHeight: function(){
36135 return this.minHeight;
36148 Roo.bootstrap.layout.North = function(config)
36150 config.region = 'north';
36151 config.cursor = 'n-resize';
36153 Roo.bootstrap.layout.Split.call(this, config);
36157 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36158 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36159 this.split.el.addClass("roo-layout-split-v");
36161 var size = config.initialSize || config.height;
36162 if(typeof size != "undefined"){
36163 this.el.setHeight(size);
36166 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36168 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36172 getBox : function(){
36173 if(this.collapsed){
36174 return this.collapsedEl.getBox();
36176 var box = this.el.getBox();
36178 box.height += this.split.el.getHeight();
36183 updateBox : function(box){
36184 if(this.split && !this.collapsed){
36185 box.height -= this.split.el.getHeight();
36186 this.split.el.setLeft(box.x);
36187 this.split.el.setTop(box.y+box.height);
36188 this.split.el.setWidth(box.width);
36190 if(this.collapsed){
36191 this.updateBody(box.width, null);
36193 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36201 Roo.bootstrap.layout.South = function(config){
36202 config.region = 'south';
36203 config.cursor = 's-resize';
36204 Roo.bootstrap.layout.Split.call(this, config);
36206 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36207 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36208 this.split.el.addClass("roo-layout-split-v");
36210 var size = config.initialSize || config.height;
36211 if(typeof size != "undefined"){
36212 this.el.setHeight(size);
36216 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36217 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36218 getBox : function(){
36219 if(this.collapsed){
36220 return this.collapsedEl.getBox();
36222 var box = this.el.getBox();
36224 var sh = this.split.el.getHeight();
36231 updateBox : function(box){
36232 if(this.split && !this.collapsed){
36233 var sh = this.split.el.getHeight();
36236 this.split.el.setLeft(box.x);
36237 this.split.el.setTop(box.y-sh);
36238 this.split.el.setWidth(box.width);
36240 if(this.collapsed){
36241 this.updateBody(box.width, null);
36243 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36247 Roo.bootstrap.layout.East = function(config){
36248 config.region = "east";
36249 config.cursor = "e-resize";
36250 Roo.bootstrap.layout.Split.call(this, config);
36252 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36253 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36254 this.split.el.addClass("roo-layout-split-h");
36256 var size = config.initialSize || config.width;
36257 if(typeof size != "undefined"){
36258 this.el.setWidth(size);
36261 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36262 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36263 getBox : function(){
36264 if(this.collapsed){
36265 return this.collapsedEl.getBox();
36267 var box = this.el.getBox();
36269 var sw = this.split.el.getWidth();
36276 updateBox : function(box){
36277 if(this.split && !this.collapsed){
36278 var sw = this.split.el.getWidth();
36280 this.split.el.setLeft(box.x);
36281 this.split.el.setTop(box.y);
36282 this.split.el.setHeight(box.height);
36285 if(this.collapsed){
36286 this.updateBody(null, box.height);
36288 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36292 Roo.bootstrap.layout.West = function(config){
36293 config.region = "west";
36294 config.cursor = "w-resize";
36296 Roo.bootstrap.layout.Split.call(this, config);
36298 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36299 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36300 this.split.el.addClass("roo-layout-split-h");
36304 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36305 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36307 onRender: function(ctr, pos)
36309 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36310 var size = this.config.initialSize || this.config.width;
36311 if(typeof size != "undefined"){
36312 this.el.setWidth(size);
36316 getBox : function(){
36317 if(this.collapsed){
36318 return this.collapsedEl.getBox();
36320 var box = this.el.getBox();
36322 box.width += this.split.el.getWidth();
36327 updateBox : function(box){
36328 if(this.split && !this.collapsed){
36329 var sw = this.split.el.getWidth();
36331 this.split.el.setLeft(box.x+box.width);
36332 this.split.el.setTop(box.y);
36333 this.split.el.setHeight(box.height);
36335 if(this.collapsed){
36336 this.updateBody(null, box.height);
36338 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36341 Roo.namespace("Roo.bootstrap.panel");/*
36343 * Ext JS Library 1.1.1
36344 * Copyright(c) 2006-2007, Ext JS, LLC.
36346 * Originally Released Under LGPL - original licence link has changed is not relivant.
36349 * <script type="text/javascript">
36352 * @class Roo.ContentPanel
36353 * @extends Roo.util.Observable
36354 * A basic ContentPanel element.
36355 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36356 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36357 * @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
36358 * @cfg {Boolean} closable True if the panel can be closed/removed
36359 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36360 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36361 * @cfg {Toolbar} toolbar A toolbar for this panel
36362 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36363 * @cfg {String} title The title for this panel
36364 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36365 * @cfg {String} url Calls {@link #setUrl} with this value
36366 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36367 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36368 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36369 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36370 * @cfg {Boolean} badges render the badges
36373 * Create a new ContentPanel.
36374 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36375 * @param {String/Object} config A string to set only the title or a config object
36376 * @param {String} content (optional) Set the HTML content for this panel
36377 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36379 Roo.bootstrap.panel.Content = function( config){
36381 this.tpl = config.tpl || false;
36383 var el = config.el;
36384 var content = config.content;
36386 if(config.autoCreate){ // xtype is available if this is called from factory
36389 this.el = Roo.get(el);
36390 if(!this.el && config && config.autoCreate){
36391 if(typeof config.autoCreate == "object"){
36392 if(!config.autoCreate.id){
36393 config.autoCreate.id = config.id||el;
36395 this.el = Roo.DomHelper.append(document.body,
36396 config.autoCreate, true);
36398 var elcfg = { tag: "div",
36399 cls: "roo-layout-inactive-content",
36403 elcfg.html = config.html;
36407 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36410 this.closable = false;
36411 this.loaded = false;
36412 this.active = false;
36415 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36417 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36419 this.wrapEl = this.el; //this.el.wrap();
36421 if (config.toolbar.items) {
36422 ti = config.toolbar.items ;
36423 delete config.toolbar.items ;
36427 this.toolbar.render(this.wrapEl, 'before');
36428 for(var i =0;i < ti.length;i++) {
36429 // Roo.log(['add child', items[i]]);
36430 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36432 this.toolbar.items = nitems;
36433 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36434 delete config.toolbar;
36438 // xtype created footer. - not sure if will work as we normally have to render first..
36439 if (this.footer && !this.footer.el && this.footer.xtype) {
36440 if (!this.wrapEl) {
36441 this.wrapEl = this.el.wrap();
36444 this.footer.container = this.wrapEl.createChild();
36446 this.footer = Roo.factory(this.footer, Roo);
36451 if(typeof config == "string"){
36452 this.title = config;
36454 Roo.apply(this, config);
36458 this.resizeEl = Roo.get(this.resizeEl, true);
36460 this.resizeEl = this.el;
36462 // handle view.xtype
36470 * Fires when this panel is activated.
36471 * @param {Roo.ContentPanel} this
36475 * @event deactivate
36476 * Fires when this panel is activated.
36477 * @param {Roo.ContentPanel} this
36479 "deactivate" : true,
36483 * Fires when this panel is resized if fitToFrame is true.
36484 * @param {Roo.ContentPanel} this
36485 * @param {Number} width The width after any component adjustments
36486 * @param {Number} height The height after any component adjustments
36492 * Fires when this tab is created
36493 * @param {Roo.ContentPanel} this
36504 if(this.autoScroll){
36505 this.resizeEl.setStyle("overflow", "auto");
36507 // fix randome scrolling
36508 //this.el.on('scroll', function() {
36509 // Roo.log('fix random scolling');
36510 // this.scrollTo('top',0);
36513 content = content || this.content;
36515 this.setContent(content);
36517 if(config && config.url){
36518 this.setUrl(this.url, this.params, this.loadOnce);
36523 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36525 if (this.view && typeof(this.view.xtype) != 'undefined') {
36526 this.view.el = this.el.appendChild(document.createElement("div"));
36527 this.view = Roo.factory(this.view);
36528 this.view.render && this.view.render(false, '');
36532 this.fireEvent('render', this);
36535 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36539 setRegion : function(region){
36540 this.region = region;
36541 this.setActiveClass(region && !this.background);
36545 setActiveClass: function(state)
36548 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36549 this.el.setStyle('position','relative');
36551 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36552 this.el.setStyle('position', 'absolute');
36557 * Returns the toolbar for this Panel if one was configured.
36558 * @return {Roo.Toolbar}
36560 getToolbar : function(){
36561 return this.toolbar;
36564 setActiveState : function(active)
36566 this.active = active;
36567 this.setActiveClass(active);
36569 if(this.fireEvent("deactivate", this) === false){
36574 this.fireEvent("activate", this);
36578 * Updates this panel's element
36579 * @param {String} content The new content
36580 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36582 setContent : function(content, loadScripts){
36583 this.el.update(content, loadScripts);
36586 ignoreResize : function(w, h){
36587 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36590 this.lastSize = {width: w, height: h};
36595 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36596 * @return {Roo.UpdateManager} The UpdateManager
36598 getUpdateManager : function(){
36599 return this.el.getUpdateManager();
36602 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36603 * @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:
36606 url: "your-url.php",
36607 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36608 callback: yourFunction,
36609 scope: yourObject, //(optional scope)
36612 text: "Loading...",
36617 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36618 * 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.
36619 * @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}
36620 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36621 * @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.
36622 * @return {Roo.ContentPanel} this
36625 var um = this.el.getUpdateManager();
36626 um.update.apply(um, arguments);
36632 * 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.
36633 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36634 * @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)
36635 * @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)
36636 * @return {Roo.UpdateManager} The UpdateManager
36638 setUrl : function(url, params, loadOnce){
36639 if(this.refreshDelegate){
36640 this.removeListener("activate", this.refreshDelegate);
36642 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36643 this.on("activate", this.refreshDelegate);
36644 return this.el.getUpdateManager();
36647 _handleRefresh : function(url, params, loadOnce){
36648 if(!loadOnce || !this.loaded){
36649 var updater = this.el.getUpdateManager();
36650 updater.update(url, params, this._setLoaded.createDelegate(this));
36654 _setLoaded : function(){
36655 this.loaded = true;
36659 * Returns this panel's id
36662 getId : function(){
36667 * Returns this panel's element - used by regiosn to add.
36668 * @return {Roo.Element}
36670 getEl : function(){
36671 return this.wrapEl || this.el;
36676 adjustForComponents : function(width, height)
36678 //Roo.log('adjustForComponents ');
36679 if(this.resizeEl != this.el){
36680 width -= this.el.getFrameWidth('lr');
36681 height -= this.el.getFrameWidth('tb');
36684 var te = this.toolbar.getEl();
36685 te.setWidth(width);
36686 height -= te.getHeight();
36689 var te = this.footer.getEl();
36690 te.setWidth(width);
36691 height -= te.getHeight();
36695 if(this.adjustments){
36696 width += this.adjustments[0];
36697 height += this.adjustments[1];
36699 return {"width": width, "height": height};
36702 setSize : function(width, height){
36703 if(this.fitToFrame && !this.ignoreResize(width, height)){
36704 if(this.fitContainer && this.resizeEl != this.el){
36705 this.el.setSize(width, height);
36707 var size = this.adjustForComponents(width, height);
36708 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36709 this.fireEvent('resize', this, size.width, size.height);
36714 * Returns this panel's title
36717 getTitle : function(){
36719 if (typeof(this.title) != 'object') {
36724 for (var k in this.title) {
36725 if (!this.title.hasOwnProperty(k)) {
36729 if (k.indexOf('-') >= 0) {
36730 var s = k.split('-');
36731 for (var i = 0; i<s.length; i++) {
36732 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36735 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36742 * Set this panel's title
36743 * @param {String} title
36745 setTitle : function(title){
36746 this.title = title;
36748 this.region.updatePanelTitle(this, title);
36753 * Returns true is this panel was configured to be closable
36754 * @return {Boolean}
36756 isClosable : function(){
36757 return this.closable;
36760 beforeSlide : function(){
36762 this.resizeEl.clip();
36765 afterSlide : function(){
36767 this.resizeEl.unclip();
36771 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36772 * Will fail silently if the {@link #setUrl} method has not been called.
36773 * This does not activate the panel, just updates its content.
36775 refresh : function(){
36776 if(this.refreshDelegate){
36777 this.loaded = false;
36778 this.refreshDelegate();
36783 * Destroys this panel
36785 destroy : function(){
36786 this.el.removeAllListeners();
36787 var tempEl = document.createElement("span");
36788 tempEl.appendChild(this.el.dom);
36789 tempEl.innerHTML = "";
36795 * form - if the content panel contains a form - this is a reference to it.
36796 * @type {Roo.form.Form}
36800 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36801 * This contains a reference to it.
36807 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36817 * @param {Object} cfg Xtype definition of item to add.
36821 getChildContainer: function () {
36822 return this.getEl();
36827 var ret = new Roo.factory(cfg);
36832 if (cfg.xtype.match(/^Form$/)) {
36835 //if (this.footer) {
36836 // el = this.footer.container.insertSibling(false, 'before');
36838 el = this.el.createChild();
36841 this.form = new Roo.form.Form(cfg);
36844 if ( this.form.allItems.length) {
36845 this.form.render(el.dom);
36849 // should only have one of theses..
36850 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36851 // views.. should not be just added - used named prop 'view''
36853 cfg.el = this.el.appendChild(document.createElement("div"));
36856 var ret = new Roo.factory(cfg);
36858 ret.render && ret.render(false, ''); // render blank..
36868 * @class Roo.bootstrap.panel.Grid
36869 * @extends Roo.bootstrap.panel.Content
36871 * Create a new GridPanel.
36872 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36873 * @param {Object} config A the config object
36879 Roo.bootstrap.panel.Grid = function(config)
36883 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36884 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36886 config.el = this.wrapper;
36887 //this.el = this.wrapper;
36889 if (config.container) {
36890 // ctor'ed from a Border/panel.grid
36893 this.wrapper.setStyle("overflow", "hidden");
36894 this.wrapper.addClass('roo-grid-container');
36899 if(config.toolbar){
36900 var tool_el = this.wrapper.createChild();
36901 this.toolbar = Roo.factory(config.toolbar);
36903 if (config.toolbar.items) {
36904 ti = config.toolbar.items ;
36905 delete config.toolbar.items ;
36909 this.toolbar.render(tool_el);
36910 for(var i =0;i < ti.length;i++) {
36911 // Roo.log(['add child', items[i]]);
36912 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36914 this.toolbar.items = nitems;
36916 delete config.toolbar;
36919 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36920 config.grid.scrollBody = true;;
36921 config.grid.monitorWindowResize = false; // turn off autosizing
36922 config.grid.autoHeight = false;
36923 config.grid.autoWidth = false;
36925 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36927 if (config.background) {
36928 // render grid on panel activation (if panel background)
36929 this.on('activate', function(gp) {
36930 if (!gp.grid.rendered) {
36931 gp.grid.render(this.wrapper);
36932 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36937 this.grid.render(this.wrapper);
36938 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36941 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36942 // ??? needed ??? config.el = this.wrapper;
36947 // xtype created footer. - not sure if will work as we normally have to render first..
36948 if (this.footer && !this.footer.el && this.footer.xtype) {
36950 var ctr = this.grid.getView().getFooterPanel(true);
36951 this.footer.dataSource = this.grid.dataSource;
36952 this.footer = Roo.factory(this.footer, Roo);
36953 this.footer.render(ctr);
36963 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36964 getId : function(){
36965 return this.grid.id;
36969 * Returns the grid for this panel
36970 * @return {Roo.bootstrap.Table}
36972 getGrid : function(){
36976 setSize : function(width, height){
36977 if(!this.ignoreResize(width, height)){
36978 var grid = this.grid;
36979 var size = this.adjustForComponents(width, height);
36980 var gridel = grid.getGridEl();
36981 gridel.setSize(size.width, size.height);
36983 var thd = grid.getGridEl().select('thead',true).first();
36984 var tbd = grid.getGridEl().select('tbody', true).first();
36986 tbd.setSize(width, height - thd.getHeight());
36995 beforeSlide : function(){
36996 this.grid.getView().scroller.clip();
36999 afterSlide : function(){
37000 this.grid.getView().scroller.unclip();
37003 destroy : function(){
37004 this.grid.destroy();
37006 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37011 * @class Roo.bootstrap.panel.Nest
37012 * @extends Roo.bootstrap.panel.Content
37014 * Create a new Panel, that can contain a layout.Border.
37017 * @param {Roo.BorderLayout} layout The layout for this panel
37018 * @param {String/Object} config A string to set only the title or a config object
37020 Roo.bootstrap.panel.Nest = function(config)
37022 // construct with only one argument..
37023 /* FIXME - implement nicer consturctors
37024 if (layout.layout) {
37026 layout = config.layout;
37027 delete config.layout;
37029 if (layout.xtype && !layout.getEl) {
37030 // then layout needs constructing..
37031 layout = Roo.factory(layout, Roo);
37035 config.el = config.layout.getEl();
37037 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37039 config.layout.monitorWindowResize = false; // turn off autosizing
37040 this.layout = config.layout;
37041 this.layout.getEl().addClass("roo-layout-nested-layout");
37048 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37050 setSize : function(width, height){
37051 if(!this.ignoreResize(width, height)){
37052 var size = this.adjustForComponents(width, height);
37053 var el = this.layout.getEl();
37054 if (size.height < 1) {
37055 el.setWidth(size.width);
37057 el.setSize(size.width, size.height);
37059 var touch = el.dom.offsetWidth;
37060 this.layout.layout();
37061 // ie requires a double layout on the first pass
37062 if(Roo.isIE && !this.initialized){
37063 this.initialized = true;
37064 this.layout.layout();
37069 // activate all subpanels if not currently active..
37071 setActiveState : function(active){
37072 this.active = active;
37073 this.setActiveClass(active);
37076 this.fireEvent("deactivate", this);
37080 this.fireEvent("activate", this);
37081 // not sure if this should happen before or after..
37082 if (!this.layout) {
37083 return; // should not happen..
37086 for (var r in this.layout.regions) {
37087 reg = this.layout.getRegion(r);
37088 if (reg.getActivePanel()) {
37089 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37090 reg.setActivePanel(reg.getActivePanel());
37093 if (!reg.panels.length) {
37096 reg.showPanel(reg.getPanel(0));
37105 * Returns the nested BorderLayout for this panel
37106 * @return {Roo.BorderLayout}
37108 getLayout : function(){
37109 return this.layout;
37113 * Adds a xtype elements to the layout of the nested panel
37117 xtype : 'ContentPanel',
37124 xtype : 'NestedLayoutPanel',
37130 items : [ ... list of content panels or nested layout panels.. ]
37134 * @param {Object} cfg Xtype definition of item to add.
37136 addxtype : function(cfg) {
37137 return this.layout.addxtype(cfg);
37142 * Ext JS Library 1.1.1
37143 * Copyright(c) 2006-2007, Ext JS, LLC.
37145 * Originally Released Under LGPL - original licence link has changed is not relivant.
37148 * <script type="text/javascript">
37151 * @class Roo.TabPanel
37152 * @extends Roo.util.Observable
37153 * A lightweight tab container.
37157 // basic tabs 1, built from existing content
37158 var tabs = new Roo.TabPanel("tabs1");
37159 tabs.addTab("script", "View Script");
37160 tabs.addTab("markup", "View Markup");
37161 tabs.activate("script");
37163 // more advanced tabs, built from javascript
37164 var jtabs = new Roo.TabPanel("jtabs");
37165 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37167 // set up the UpdateManager
37168 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37169 var updater = tab2.getUpdateManager();
37170 updater.setDefaultUrl("ajax1.htm");
37171 tab2.on('activate', updater.refresh, updater, true);
37173 // Use setUrl for Ajax loading
37174 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37175 tab3.setUrl("ajax2.htm", null, true);
37178 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37181 jtabs.activate("jtabs-1");
37184 * Create a new TabPanel.
37185 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37186 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37188 Roo.bootstrap.panel.Tabs = function(config){
37190 * The container element for this TabPanel.
37191 * @type Roo.Element
37193 this.el = Roo.get(config.el);
37196 if(typeof config == "boolean"){
37197 this.tabPosition = config ? "bottom" : "top";
37199 Roo.apply(this, config);
37203 if(this.tabPosition == "bottom"){
37204 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37205 this.el.addClass("roo-tabs-bottom");
37207 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37208 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37209 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37211 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37213 if(this.tabPosition != "bottom"){
37214 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37215 * @type Roo.Element
37217 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37218 this.el.addClass("roo-tabs-top");
37222 this.bodyEl.setStyle("position", "relative");
37224 this.active = null;
37225 this.activateDelegate = this.activate.createDelegate(this);
37230 * Fires when the active tab changes
37231 * @param {Roo.TabPanel} this
37232 * @param {Roo.TabPanelItem} activePanel The new active tab
37236 * @event beforetabchange
37237 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37238 * @param {Roo.TabPanel} this
37239 * @param {Object} e Set cancel to true on this object to cancel the tab change
37240 * @param {Roo.TabPanelItem} tab The tab being changed to
37242 "beforetabchange" : true
37245 Roo.EventManager.onWindowResize(this.onResize, this);
37246 this.cpad = this.el.getPadding("lr");
37247 this.hiddenCount = 0;
37250 // toolbar on the tabbar support...
37251 if (this.toolbar) {
37252 alert("no toolbar support yet");
37253 this.toolbar = false;
37255 var tcfg = this.toolbar;
37256 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37257 this.toolbar = new Roo.Toolbar(tcfg);
37258 if (Roo.isSafari) {
37259 var tbl = tcfg.container.child('table', true);
37260 tbl.setAttribute('width', '100%');
37268 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37271 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37273 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37275 tabPosition : "top",
37277 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37279 currentTabWidth : 0,
37281 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37285 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37289 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37291 preferredTabWidth : 175,
37293 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37295 resizeTabs : false,
37297 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37299 monitorResize : true,
37301 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37306 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37307 * @param {String} id The id of the div to use <b>or create</b>
37308 * @param {String} text The text for the tab
37309 * @param {String} content (optional) Content to put in the TabPanelItem body
37310 * @param {Boolean} closable (optional) True to create a close icon on the tab
37311 * @return {Roo.TabPanelItem} The created TabPanelItem
37313 addTab : function(id, text, content, closable, tpl)
37315 var item = new Roo.bootstrap.panel.TabItem({
37319 closable : closable,
37322 this.addTabItem(item);
37324 item.setContent(content);
37330 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37331 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37332 * @return {Roo.TabPanelItem}
37334 getTab : function(id){
37335 return this.items[id];
37339 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37340 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37342 hideTab : function(id){
37343 var t = this.items[id];
37346 this.hiddenCount++;
37347 this.autoSizeTabs();
37352 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37353 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37355 unhideTab : function(id){
37356 var t = this.items[id];
37358 t.setHidden(false);
37359 this.hiddenCount--;
37360 this.autoSizeTabs();
37365 * Adds an existing {@link Roo.TabPanelItem}.
37366 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37368 addTabItem : function(item){
37369 this.items[item.id] = item;
37370 this.items.push(item);
37371 // if(this.resizeTabs){
37372 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37373 // this.autoSizeTabs();
37375 // item.autoSize();
37380 * Removes a {@link Roo.TabPanelItem}.
37381 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37383 removeTab : function(id){
37384 var items = this.items;
37385 var tab = items[id];
37386 if(!tab) { return; }
37387 var index = items.indexOf(tab);
37388 if(this.active == tab && items.length > 1){
37389 var newTab = this.getNextAvailable(index);
37394 this.stripEl.dom.removeChild(tab.pnode.dom);
37395 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37396 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37398 items.splice(index, 1);
37399 delete this.items[tab.id];
37400 tab.fireEvent("close", tab);
37401 tab.purgeListeners();
37402 this.autoSizeTabs();
37405 getNextAvailable : function(start){
37406 var items = this.items;
37408 // look for a next tab that will slide over to
37409 // replace the one being removed
37410 while(index < items.length){
37411 var item = items[++index];
37412 if(item && !item.isHidden()){
37416 // if one isn't found select the previous tab (on the left)
37419 var item = items[--index];
37420 if(item && !item.isHidden()){
37428 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37429 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37431 disableTab : function(id){
37432 var tab = this.items[id];
37433 if(tab && this.active != tab){
37439 * Enables a {@link Roo.TabPanelItem} that is disabled.
37440 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37442 enableTab : function(id){
37443 var tab = this.items[id];
37448 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37449 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37450 * @return {Roo.TabPanelItem} The TabPanelItem.
37452 activate : function(id){
37453 var tab = this.items[id];
37457 if(tab == this.active || tab.disabled){
37461 this.fireEvent("beforetabchange", this, e, tab);
37462 if(e.cancel !== true && !tab.disabled){
37464 this.active.hide();
37466 this.active = this.items[id];
37467 this.active.show();
37468 this.fireEvent("tabchange", this, this.active);
37474 * Gets the active {@link Roo.TabPanelItem}.
37475 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37477 getActiveTab : function(){
37478 return this.active;
37482 * Updates the tab body element to fit the height of the container element
37483 * for overflow scrolling
37484 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37486 syncHeight : function(targetHeight){
37487 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37488 var bm = this.bodyEl.getMargins();
37489 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37490 this.bodyEl.setHeight(newHeight);
37494 onResize : function(){
37495 if(this.monitorResize){
37496 this.autoSizeTabs();
37501 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37503 beginUpdate : function(){
37504 this.updating = true;
37508 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37510 endUpdate : function(){
37511 this.updating = false;
37512 this.autoSizeTabs();
37516 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37518 autoSizeTabs : function(){
37519 var count = this.items.length;
37520 var vcount = count - this.hiddenCount;
37521 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37524 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37525 var availWidth = Math.floor(w / vcount);
37526 var b = this.stripBody;
37527 if(b.getWidth() > w){
37528 var tabs = this.items;
37529 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37530 if(availWidth < this.minTabWidth){
37531 /*if(!this.sleft){ // incomplete scrolling code
37532 this.createScrollButtons();
37535 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37538 if(this.currentTabWidth < this.preferredTabWidth){
37539 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37545 * Returns the number of tabs in this TabPanel.
37548 getCount : function(){
37549 return this.items.length;
37553 * Resizes all the tabs to the passed width
37554 * @param {Number} The new width
37556 setTabWidth : function(width){
37557 this.currentTabWidth = width;
37558 for(var i = 0, len = this.items.length; i < len; i++) {
37559 if(!this.items[i].isHidden()) {
37560 this.items[i].setWidth(width);
37566 * Destroys this TabPanel
37567 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37569 destroy : function(removeEl){
37570 Roo.EventManager.removeResizeListener(this.onResize, this);
37571 for(var i = 0, len = this.items.length; i < len; i++){
37572 this.items[i].purgeListeners();
37574 if(removeEl === true){
37575 this.el.update("");
37580 createStrip : function(container)
37582 var strip = document.createElement("nav");
37583 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37584 container.appendChild(strip);
37588 createStripList : function(strip)
37590 // div wrapper for retard IE
37591 // returns the "tr" element.
37592 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37593 //'<div class="x-tabs-strip-wrap">'+
37594 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37595 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37596 return strip.firstChild; //.firstChild.firstChild.firstChild;
37598 createBody : function(container)
37600 var body = document.createElement("div");
37601 Roo.id(body, "tab-body");
37602 //Roo.fly(body).addClass("x-tabs-body");
37603 Roo.fly(body).addClass("tab-content");
37604 container.appendChild(body);
37607 createItemBody :function(bodyEl, id){
37608 var body = Roo.getDom(id);
37610 body = document.createElement("div");
37613 //Roo.fly(body).addClass("x-tabs-item-body");
37614 Roo.fly(body).addClass("tab-pane");
37615 bodyEl.insertBefore(body, bodyEl.firstChild);
37619 createStripElements : function(stripEl, text, closable, tpl)
37621 var td = document.createElement("li"); // was td..
37624 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37627 stripEl.appendChild(td);
37629 td.className = "x-tabs-closable";
37630 if(!this.closeTpl){
37631 this.closeTpl = new Roo.Template(
37632 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37633 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37634 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37637 var el = this.closeTpl.overwrite(td, {"text": text});
37638 var close = el.getElementsByTagName("div")[0];
37639 var inner = el.getElementsByTagName("em")[0];
37640 return {"el": el, "close": close, "inner": inner};
37643 // not sure what this is..
37644 // if(!this.tabTpl){
37645 //this.tabTpl = new Roo.Template(
37646 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37647 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37649 // this.tabTpl = new Roo.Template(
37650 // '<a href="#">' +
37651 // '<span unselectable="on"' +
37652 // (this.disableTooltips ? '' : ' title="{text}"') +
37653 // ' >{text}</span></a>'
37659 var template = tpl || this.tabTpl || false;
37663 template = new Roo.Template(
37665 '<span unselectable="on"' +
37666 (this.disableTooltips ? '' : ' title="{text}"') +
37667 ' >{text}</span></a>'
37671 switch (typeof(template)) {
37675 template = new Roo.Template(template);
37681 var el = template.overwrite(td, {"text": text});
37683 var inner = el.getElementsByTagName("span")[0];
37685 return {"el": el, "inner": inner};
37693 * @class Roo.TabPanelItem
37694 * @extends Roo.util.Observable
37695 * Represents an individual item (tab plus body) in a TabPanel.
37696 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37697 * @param {String} id The id of this TabPanelItem
37698 * @param {String} text The text for the tab of this TabPanelItem
37699 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37701 Roo.bootstrap.panel.TabItem = function(config){
37703 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37704 * @type Roo.TabPanel
37706 this.tabPanel = config.panel;
37708 * The id for this TabPanelItem
37711 this.id = config.id;
37713 this.disabled = false;
37715 this.text = config.text;
37717 this.loaded = false;
37718 this.closable = config.closable;
37721 * The body element for this TabPanelItem.
37722 * @type Roo.Element
37724 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37725 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37726 this.bodyEl.setStyle("display", "block");
37727 this.bodyEl.setStyle("zoom", "1");
37728 //this.hideAction();
37730 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37732 this.el = Roo.get(els.el);
37733 this.inner = Roo.get(els.inner, true);
37734 this.textEl = Roo.get(this.el.dom.firstChild, true);
37735 this.pnode = Roo.get(els.el.parentNode, true);
37736 // this.el.on("mousedown", this.onTabMouseDown, this);
37737 this.el.on("click", this.onTabClick, this);
37739 if(config.closable){
37740 var c = Roo.get(els.close, true);
37741 c.dom.title = this.closeText;
37742 c.addClassOnOver("close-over");
37743 c.on("click", this.closeClick, this);
37749 * Fires when this tab becomes the active tab.
37750 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37751 * @param {Roo.TabPanelItem} this
37755 * @event beforeclose
37756 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37757 * @param {Roo.TabPanelItem} this
37758 * @param {Object} e Set cancel to true on this object to cancel the close.
37760 "beforeclose": true,
37763 * Fires when this tab is closed.
37764 * @param {Roo.TabPanelItem} this
37768 * @event deactivate
37769 * Fires when this tab is no longer the active tab.
37770 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37771 * @param {Roo.TabPanelItem} this
37773 "deactivate" : true
37775 this.hidden = false;
37777 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37780 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37782 purgeListeners : function(){
37783 Roo.util.Observable.prototype.purgeListeners.call(this);
37784 this.el.removeAllListeners();
37787 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37790 this.pnode.addClass("active");
37793 this.tabPanel.stripWrap.repaint();
37795 this.fireEvent("activate", this.tabPanel, this);
37799 * Returns true if this tab is the active tab.
37800 * @return {Boolean}
37802 isActive : function(){
37803 return this.tabPanel.getActiveTab() == this;
37807 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37810 this.pnode.removeClass("active");
37812 this.fireEvent("deactivate", this.tabPanel, this);
37815 hideAction : function(){
37816 this.bodyEl.hide();
37817 this.bodyEl.setStyle("position", "absolute");
37818 this.bodyEl.setLeft("-20000px");
37819 this.bodyEl.setTop("-20000px");
37822 showAction : function(){
37823 this.bodyEl.setStyle("position", "relative");
37824 this.bodyEl.setTop("");
37825 this.bodyEl.setLeft("");
37826 this.bodyEl.show();
37830 * Set the tooltip for the tab.
37831 * @param {String} tooltip The tab's tooltip
37833 setTooltip : function(text){
37834 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37835 this.textEl.dom.qtip = text;
37836 this.textEl.dom.removeAttribute('title');
37838 this.textEl.dom.title = text;
37842 onTabClick : function(e){
37843 e.preventDefault();
37844 this.tabPanel.activate(this.id);
37847 onTabMouseDown : function(e){
37848 e.preventDefault();
37849 this.tabPanel.activate(this.id);
37852 getWidth : function(){
37853 return this.inner.getWidth();
37856 setWidth : function(width){
37857 var iwidth = width - this.pnode.getPadding("lr");
37858 this.inner.setWidth(iwidth);
37859 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37860 this.pnode.setWidth(width);
37864 * Show or hide the tab
37865 * @param {Boolean} hidden True to hide or false to show.
37867 setHidden : function(hidden){
37868 this.hidden = hidden;
37869 this.pnode.setStyle("display", hidden ? "none" : "");
37873 * Returns true if this tab is "hidden"
37874 * @return {Boolean}
37876 isHidden : function(){
37877 return this.hidden;
37881 * Returns the text for this tab
37884 getText : function(){
37888 autoSize : function(){
37889 //this.el.beginMeasure();
37890 this.textEl.setWidth(1);
37892 * #2804 [new] Tabs in Roojs
37893 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37895 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37896 //this.el.endMeasure();
37900 * Sets the text for the tab (Note: this also sets the tooltip text)
37901 * @param {String} text The tab's text and tooltip
37903 setText : function(text){
37905 this.textEl.update(text);
37906 this.setTooltip(text);
37907 //if(!this.tabPanel.resizeTabs){
37908 // this.autoSize();
37912 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37914 activate : function(){
37915 this.tabPanel.activate(this.id);
37919 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37921 disable : function(){
37922 if(this.tabPanel.active != this){
37923 this.disabled = true;
37924 this.pnode.addClass("disabled");
37929 * Enables this TabPanelItem if it was previously disabled.
37931 enable : function(){
37932 this.disabled = false;
37933 this.pnode.removeClass("disabled");
37937 * Sets the content for this TabPanelItem.
37938 * @param {String} content The content
37939 * @param {Boolean} loadScripts true to look for and load scripts
37941 setContent : function(content, loadScripts){
37942 this.bodyEl.update(content, loadScripts);
37946 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37947 * @return {Roo.UpdateManager} The UpdateManager
37949 getUpdateManager : function(){
37950 return this.bodyEl.getUpdateManager();
37954 * Set a URL to be used to load the content for this TabPanelItem.
37955 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37956 * @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)
37957 * @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)
37958 * @return {Roo.UpdateManager} The UpdateManager
37960 setUrl : function(url, params, loadOnce){
37961 if(this.refreshDelegate){
37962 this.un('activate', this.refreshDelegate);
37964 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37965 this.on("activate", this.refreshDelegate);
37966 return this.bodyEl.getUpdateManager();
37970 _handleRefresh : function(url, params, loadOnce){
37971 if(!loadOnce || !this.loaded){
37972 var updater = this.bodyEl.getUpdateManager();
37973 updater.update(url, params, this._setLoaded.createDelegate(this));
37978 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37979 * Will fail silently if the setUrl method has not been called.
37980 * This does not activate the panel, just updates its content.
37982 refresh : function(){
37983 if(this.refreshDelegate){
37984 this.loaded = false;
37985 this.refreshDelegate();
37990 _setLoaded : function(){
37991 this.loaded = true;
37995 closeClick : function(e){
37998 this.fireEvent("beforeclose", this, o);
37999 if(o.cancel !== true){
38000 this.tabPanel.removeTab(this.id);
38004 * The text displayed in the tooltip for the close icon.
38007 closeText : "Close this tab"
38010 * This script refer to:
38011 * Title: International Telephone Input
38012 * Author: Jack O'Connor
38013 * Code version: v12.1.12
38014 * Availability: https://github.com/jackocnr/intl-tel-input.git
38017 Roo.bootstrap.PhoneInputData = function() {
38020 "Afghanistan (افغانستان)",
38025 "Albania (Shqipëri)",
38030 "Algeria (الجزائر)",
38055 "Antigua and Barbuda",
38065 "Armenia (Հայաստան)",
38081 "Austria (Österreich)",
38086 "Azerbaijan (Azərbaycan)",
38096 "Bahrain (البحرين)",
38101 "Bangladesh (বাংলাদেশ)",
38111 "Belarus (Беларусь)",
38116 "Belgium (België)",
38146 "Bosnia and Herzegovina (Босна и Херцеговина)",
38161 "British Indian Ocean Territory",
38166 "British Virgin Islands",
38176 "Bulgaria (България)",
38186 "Burundi (Uburundi)",
38191 "Cambodia (កម្ពុជា)",
38196 "Cameroon (Cameroun)",
38205 ["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"]
38208 "Cape Verde (Kabu Verdi)",
38213 "Caribbean Netherlands",
38224 "Central African Republic (République centrafricaine)",
38244 "Christmas Island",
38250 "Cocos (Keeling) Islands",
38261 "Comoros (جزر القمر)",
38266 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38271 "Congo (Republic) (Congo-Brazzaville)",
38291 "Croatia (Hrvatska)",
38312 "Czech Republic (Česká republika)",
38317 "Denmark (Danmark)",
38332 "Dominican Republic (República Dominicana)",
38336 ["809", "829", "849"]
38354 "Equatorial Guinea (Guinea Ecuatorial)",
38374 "Falkland Islands (Islas Malvinas)",
38379 "Faroe Islands (Føroyar)",
38400 "French Guiana (Guyane française)",
38405 "French Polynesia (Polynésie française)",
38420 "Georgia (საქართველო)",
38425 "Germany (Deutschland)",
38445 "Greenland (Kalaallit Nunaat)",
38482 "Guinea-Bissau (Guiné Bissau)",
38507 "Hungary (Magyarország)",
38512 "Iceland (Ísland)",
38532 "Iraq (العراق)",
38548 "Israel (ישראל)",
38575 "Jordan (الأردن)",
38580 "Kazakhstan (Казахстан)",
38601 "Kuwait (الكويت)",
38606 "Kyrgyzstan (Кыргызстан)",
38616 "Latvia (Latvija)",
38621 "Lebanon (لبنان)",
38636 "Libya (ليبيا)",
38646 "Lithuania (Lietuva)",
38661 "Macedonia (FYROM) (Македонија)",
38666 "Madagascar (Madagasikara)",
38696 "Marshall Islands",
38706 "Mauritania (موريتانيا)",
38711 "Mauritius (Moris)",
38732 "Moldova (Republica Moldova)",
38742 "Mongolia (Монгол)",
38747 "Montenegro (Crna Gora)",
38757 "Morocco (المغرب)",
38763 "Mozambique (Moçambique)",
38768 "Myanmar (Burma) (မြန်မာ)",
38773 "Namibia (Namibië)",
38788 "Netherlands (Nederland)",
38793 "New Caledonia (Nouvelle-Calédonie)",
38828 "North Korea (조선 민주주의 인민 공화국)",
38833 "Northern Mariana Islands",
38849 "Pakistan (پاکستان)",
38859 "Palestine (فلسطين)",
38869 "Papua New Guinea",
38911 "Réunion (La Réunion)",
38917 "Romania (România)",
38933 "Saint Barthélemy",
38944 "Saint Kitts and Nevis",
38954 "Saint Martin (Saint-Martin (partie française))",
38960 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
38965 "Saint Vincent and the Grenadines",
38980 "São Tomé and Príncipe (São Tomé e Príncipe)",
38985 "Saudi Arabia (المملكة العربية السعودية)",
38990 "Senegal (Sénégal)",
39020 "Slovakia (Slovensko)",
39025 "Slovenia (Slovenija)",
39035 "Somalia (Soomaaliya)",
39045 "South Korea (대한민국)",
39050 "South Sudan (جنوب السودان)",
39060 "Sri Lanka (ශ්රී ලංකාව)",
39065 "Sudan (السودان)",
39075 "Svalbard and Jan Mayen",
39086 "Sweden (Sverige)",
39091 "Switzerland (Schweiz)",
39096 "Syria (سوريا)",
39141 "Trinidad and Tobago",
39146 "Tunisia (تونس)",
39151 "Turkey (Türkiye)",
39161 "Turks and Caicos Islands",
39171 "U.S. Virgin Islands",
39181 "Ukraine (Україна)",
39186 "United Arab Emirates (الإمارات العربية المتحدة)",
39208 "Uzbekistan (Oʻzbekiston)",
39218 "Vatican City (Città del Vaticano)",
39229 "Vietnam (Việt Nam)",
39234 "Wallis and Futuna (Wallis-et-Futuna)",
39239 "Western Sahara (الصحراء الغربية)",
39245 "Yemen (اليمن)",
39269 * This script refer to:
39270 * Title: International Telephone Input
39271 * Author: Jack O'Connor
39272 * Code version: v12.1.12
39273 * Availability: https://github.com/jackocnr/intl-tel-input.git
39277 * @class Roo.bootstrap.PhoneInput
39278 * @extends Roo.bootstrap.TriggerField
39279 * An input with International dial-code selection
39281 * @cfg {String} defaultDialCode default '+852'
39282 * @cfg {Array} preferedCountries default []
39285 * Create a new PhoneInput.
39286 * @param {Object} config Configuration options
39289 Roo.bootstrap.PhoneInput = function(config) {
39290 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39293 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39295 listWidth: undefined,
39297 selectedClass: 'active',
39299 invalidClass : "has-warning",
39301 validClass: 'has-success',
39303 allowed: '0123456789',
39306 * @cfg {String} defaultDialCode The default dial code when initializing the input
39308 defaultDialCode: '+852',
39311 * @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
39313 preferedCountries: false,
39315 getAutoCreate : function()
39317 var data = Roo.bootstrap.PhoneInputData();
39318 var align = this.labelAlign || this.parentLabelAlign();
39321 this.allCountries = [];
39322 this.dialCodeMapping = [];
39324 for (var i = 0; i < data.length; i++) {
39326 this.allCountries[i] = {
39330 priority: c[3] || 0,
39331 areaCodes: c[4] || null
39333 this.dialCodeMapping[c[2]] = {
39336 priority: c[3] || 0,
39337 areaCodes: c[4] || null
39349 cls : 'form-control tel-input',
39350 autocomplete: 'new-password'
39353 var hiddenInput = {
39356 cls: 'hidden-tel-input'
39360 hiddenInput.name = this.name;
39363 if (this.disabled) {
39364 input.disabled = true;
39367 var flag_container = {
39384 cls: this.hasFeedback ? 'has-feedback' : '',
39390 cls: 'dial-code-holder',
39397 cls: 'roo-select2-container input-group',
39404 if (this.fieldLabel.length) {
39407 tooltip: 'This field is required'
39413 cls: 'control-label',
39419 html: this.fieldLabel
39422 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39428 if(this.indicatorpos == 'right') {
39429 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39436 if(align == 'left') {
39444 if(this.labelWidth > 12){
39445 label.style = "width: " + this.labelWidth + 'px';
39447 if(this.labelWidth < 13 && this.labelmd == 0){
39448 this.labelmd = this.labelWidth;
39450 if(this.labellg > 0){
39451 label.cls += ' col-lg-' + this.labellg;
39452 input.cls += ' col-lg-' + (12 - this.labellg);
39454 if(this.labelmd > 0){
39455 label.cls += ' col-md-' + this.labelmd;
39456 container.cls += ' col-md-' + (12 - this.labelmd);
39458 if(this.labelsm > 0){
39459 label.cls += ' col-sm-' + this.labelsm;
39460 container.cls += ' col-sm-' + (12 - this.labelsm);
39462 if(this.labelxs > 0){
39463 label.cls += ' col-xs-' + this.labelxs;
39464 container.cls += ' col-xs-' + (12 - this.labelxs);
39474 var settings = this;
39476 ['xs','sm','md','lg'].map(function(size){
39477 if (settings[size]) {
39478 cfg.cls += ' col-' + size + '-' + settings[size];
39482 this.store = new Roo.data.Store({
39483 proxy : new Roo.data.MemoryProxy({}),
39484 reader : new Roo.data.JsonReader({
39495 'name' : 'dialCode',
39499 'name' : 'priority',
39503 'name' : 'areaCodes',
39510 if(!this.preferedCountries) {
39511 this.preferedCountries = [
39518 var p = this.preferedCountries.reverse();
39521 for (var i = 0; i < p.length; i++) {
39522 for (var j = 0; j < this.allCountries.length; j++) {
39523 if(this.allCountries[j].iso2 == p[i]) {
39524 var t = this.allCountries[j];
39525 this.allCountries.splice(j,1);
39526 this.allCountries.unshift(t);
39532 this.store.proxy.data = {
39534 data: this.allCountries
39540 initEvents : function()
39543 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39545 this.indicator = this.indicatorEl();
39546 this.flag = this.flagEl();
39547 this.dialCodeHolder = this.dialCodeHolderEl();
39549 this.trigger = this.el.select('div.flag-box',true).first();
39550 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39555 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39556 _this.list.setWidth(lw);
39559 this.list.on('mouseover', this.onViewOver, this);
39560 this.list.on('mousemove', this.onViewMove, this);
39561 this.inputEl().on("keyup", this.onKeyUp, this);
39563 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39565 this.view = new Roo.View(this.list, this.tpl, {
39566 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39569 this.view.on('click', this.onViewClick, this);
39570 this.setValue(this.defaultDialCode);
39573 onTriggerClick : function(e)
39575 Roo.log('trigger click');
39580 if(this.isExpanded()){
39582 this.hasFocus = false;
39584 this.store.load({});
39585 this.hasFocus = true;
39590 isExpanded : function()
39592 return this.list.isVisible();
39595 collapse : function()
39597 if(!this.isExpanded()){
39601 Roo.get(document).un('mousedown', this.collapseIf, this);
39602 Roo.get(document).un('mousewheel', this.collapseIf, this);
39603 this.fireEvent('collapse', this);
39607 expand : function()
39611 if(this.isExpanded() || !this.hasFocus){
39615 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39616 this.list.setWidth(lw);
39619 this.restrictHeight();
39621 Roo.get(document).on('mousedown', this.collapseIf, this);
39622 Roo.get(document).on('mousewheel', this.collapseIf, this);
39624 this.fireEvent('expand', this);
39627 restrictHeight : function()
39629 this.list.alignTo(this.inputEl(), this.listAlign);
39630 this.list.alignTo(this.inputEl(), this.listAlign);
39633 onViewOver : function(e, t)
39635 if(this.inKeyMode){
39638 var item = this.view.findItemFromChild(t);
39641 var index = this.view.indexOf(item);
39642 this.select(index, false);
39647 onViewClick : function(view, doFocus, el, e)
39649 var index = this.view.getSelectedIndexes()[0];
39651 var r = this.store.getAt(index);
39654 this.onSelect(r, index);
39656 if(doFocus !== false && !this.blockFocus){
39657 this.inputEl().focus();
39661 onViewMove : function(e, t)
39663 this.inKeyMode = false;
39666 select : function(index, scrollIntoView)
39668 this.selectedIndex = index;
39669 this.view.select(index);
39670 if(scrollIntoView !== false){
39671 var el = this.view.getNode(index);
39673 this.list.scrollChildIntoView(el, false);
39678 createList : function()
39680 this.list = Roo.get(document.body).createChild({
39682 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39683 style: 'display:none'
39685 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39688 collapseIf : function(e)
39690 var in_combo = e.within(this.el);
39691 var in_list = e.within(this.list);
39692 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39694 if (in_combo || in_list || is_list) {
39700 onSelect : function(record, index)
39702 if(this.fireEvent('beforeselect', this, record, index) !== false){
39704 this.setFlagClass(record.data.iso2);
39705 this.setDialCode(record.data.dialCode);
39706 this.hasFocus = false;
39708 this.fireEvent('select', this, record, index);
39712 flagEl : function()
39714 var flag = this.el.select('div.flag',true).first();
39721 dialCodeHolderEl : function()
39723 var d = this.el.select('input.dial-code-holder',true).first();
39730 setDialCode : function(v)
39732 this.dialCodeHolder.dom.value = '+'+v;
39735 setFlagClass : function(n)
39737 this.flag.dom.className = 'flag '+n;
39740 getValue : function()
39742 var v = this.inputEl().getValue();
39743 if(this.dialCodeHolder) {
39744 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39749 setValue : function(v)
39751 var d = this.getDialCode(v);
39753 //invalid dial code
39754 if(v.length == 0 || !d || d.length == 0) {
39756 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39757 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39763 this.setFlagClass(this.dialCodeMapping[d].iso2);
39764 this.setDialCode(d);
39765 this.inputEl().dom.value = v.replace('+'+d,'');
39766 this.hiddenEl().dom.value = this.getValue();
39771 getDialCode : function(v = '')
39773 if (v.length == 0) {
39774 return this.dialCodeHolder.dom.value;
39778 if (v.charAt(0) != "+") {
39781 var numericChars = "";
39782 for (var i = 1; i < v.length; i++) {
39783 var c = v.charAt(i);
39786 if (this.dialCodeMapping[numericChars]) {
39787 dialCode = v.substr(1, i);
39789 if (numericChars.length == 4) {
39799 this.setValue(this.defaultDialCode);
39803 hiddenEl : function()
39805 return this.el.select('input.hidden-tel-input',true).first();
39808 onKeyUp : function(e){
39810 var k = e.getKey();
39811 var c = e.getCharCode();
39814 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39815 this.allowed.indexOf(String.fromCharCode(c)) === -1
39820 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39823 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39827 this.setValue(this.getValue());
39832 * @class Roo.bootstrap.MoneyField
39833 * @extends Roo.bootstrap.ComboBox
39834 * Bootstrap MoneyField class
39837 * Create a new MoneyField.
39838 * @param {Object} config Configuration options
39841 Roo.bootstrap.MoneyField = function(config) {
39843 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39847 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39850 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39852 allowDecimals : true,
39854 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39856 decimalSeparator : ".",
39858 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39860 decimalPrecision : 2,
39862 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39864 allowNegative : true,
39866 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39868 minValue : Number.NEGATIVE_INFINITY,
39870 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39872 maxValue : Number.MAX_VALUE,
39874 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39876 minText : "The minimum value for this field is {0}",
39878 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39880 maxText : "The maximum value for this field is {0}",
39882 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39883 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39885 nanText : "{0} is not a valid number",
39887 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
39898 getAutoCreate : function()
39900 var align = this.labelAlign || this.parentLabelAlign();
39912 cls : 'form-control roo-money-amount-input',
39913 autocomplete: 'new-password'
39917 input.name = this.name;
39920 if (this.disabled) {
39921 input.disabled = true;
39924 var clg = 12 - this.inputlg;
39925 var cmd = 12 - this.inputmd;
39926 var csm = 12 - this.inputsm;
39927 var cxs = 12 - this.inputxs;
39931 cls : 'row roo-money-field',
39935 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
39939 cls: 'roo-select2-container input-group',
39943 cls : 'form-control roo-money-currency-input',
39944 autocomplete: 'new-password',
39946 name : this.currencyName
39950 cls : 'input-group-addon',
39964 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
39968 cls: this.hasFeedback ? 'has-feedback' : '',
39979 if (this.fieldLabel.length) {
39982 tooltip: 'This field is required'
39988 cls: 'control-label',
39994 html: this.fieldLabel
39997 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40003 if(this.indicatorpos == 'right') {
40004 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40011 if(align == 'left') {
40019 if(this.labelWidth > 12){
40020 label.style = "width: " + this.labelWidth + 'px';
40022 if(this.labelWidth < 13 && this.labelmd == 0){
40023 this.labelmd = this.labelWidth;
40025 if(this.labellg > 0){
40026 label.cls += ' col-lg-' + this.labellg;
40027 input.cls += ' col-lg-' + (12 - this.labellg);
40029 if(this.labelmd > 0){
40030 label.cls += ' col-md-' + this.labelmd;
40031 container.cls += ' col-md-' + (12 - this.labelmd);
40033 if(this.labelsm > 0){
40034 label.cls += ' col-sm-' + this.labelsm;
40035 container.cls += ' col-sm-' + (12 - this.labelsm);
40037 if(this.labelxs > 0){
40038 label.cls += ' col-xs-' + this.labelxs;
40039 container.cls += ' col-xs-' + (12 - this.labelxs);
40049 var settings = this;
40051 ['xs','sm','md','lg'].map(function(size){
40052 if (settings[size]) {
40053 cfg.cls += ' col-' + size + '-' + settings[size];
40061 initEvents : function()
40063 this.indicator = this.indicatorEl();
40065 this.initCurrencyEvent();
40067 this.initNumberEvent();
40071 initCurrencyEvent : function()
40074 throw "can not find store for combo";
40077 this.store = Roo.factory(this.store, Roo.data);
40078 this.store.parent = this;
40082 this.triggerEl = this.el.select('.input-group-addon', true).first();
40084 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40089 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40090 _this.list.setWidth(lw);
40093 this.list.on('mouseover', this.onViewOver, this);
40094 this.list.on('mousemove', this.onViewMove, this);
40095 this.list.on('scroll', this.onViewScroll, this);
40098 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40101 this.view = new Roo.View(this.list, this.tpl, {
40102 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40105 this.view.on('click', this.onViewClick, this);
40107 this.store.on('beforeload', this.onBeforeLoad, this);
40108 this.store.on('load', this.onLoad, this);
40109 this.store.on('loadexception', this.onLoadException, this);
40111 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40112 "up" : function(e){
40113 this.inKeyMode = true;
40117 "down" : function(e){
40118 if(!this.isExpanded()){
40119 this.onTriggerClick();
40121 this.inKeyMode = true;
40126 "enter" : function(e){
40129 if(this.fireEvent("specialkey", this, e)){
40130 this.onViewClick(false);
40136 "esc" : function(e){
40140 "tab" : function(e){
40143 if(this.fireEvent("specialkey", this, e)){
40144 this.onViewClick(false);
40152 doRelay : function(foo, bar, hname){
40153 if(hname == 'down' || this.scope.isExpanded()){
40154 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40162 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40166 initNumberEvent : function(e)
40168 this.inputEl().on("keydown" , this.fireKey, this);
40169 this.inputEl().on("focus", this.onFocus, this);
40170 this.inputEl().on("blur", this.onBlur, this);
40172 this.inputEl().relayEvent('keyup', this);
40174 if(this.indicator){
40175 this.indicator.addClass('invisible');
40178 this.originalValue = this.getValue();
40180 if(this.validationEvent == 'keyup'){
40181 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40182 this.inputEl().on('keyup', this.filterValidation, this);
40184 else if(this.validationEvent !== false){
40185 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40188 if(this.selectOnFocus){
40189 this.on("focus", this.preFocus, this);
40192 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40193 this.inputEl().on("keypress", this.filterKeys, this);
40195 this.inputEl().relayEvent('keypress', this);
40198 var allowed = "0123456789";
40200 if(this.allowDecimals){
40201 allowed += this.decimalSeparator;
40204 if(this.allowNegative){
40208 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40210 var keyPress = function(e){
40212 var k = e.getKey();
40214 var c = e.getCharCode();
40217 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40218 allowed.indexOf(String.fromCharCode(c)) === -1
40224 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40228 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40233 this.inputEl().on("keypress", keyPress, this);
40237 onTriggerClick : function(e)
40244 this.loadNext = false;
40246 if(this.isExpanded()){
40251 this.hasFocus = true;
40253 if(this.triggerAction == 'all') {
40254 this.doQuery(this.allQuery, true);
40258 this.doQuery(this.getRawValue());
40261 getCurrency : function()
40263 var v = this.currencyEl().getValue();
40268 restrictHeight : function()
40270 this.list.alignTo(this.currencyEl(), this.listAlign);
40271 this.list.alignTo(this.currencyEl(), this.listAlign);
40274 onViewClick : function(view, doFocus, el, e)
40276 var index = this.view.getSelectedIndexes()[0];
40278 var r = this.store.getAt(index);
40281 this.onSelect(r, index);
40285 onSelect : function(record, index){
40287 if(this.fireEvent('beforeselect', this, record, index) !== false){
40289 this.setFromCurrencyData(index > -1 ? record.data : false);
40293 this.fireEvent('select', this, record, index);
40297 setFromCurrencyData : function(o)
40301 this.lastCurrency = o;
40303 if (this.currencyField) {
40304 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40306 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40309 this.lastSelectionText = currency;
40311 this.setCurrency(currency);
40314 setFromData : function(o)
40318 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40320 this.setFromCurrencyData(c);
40325 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40327 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40330 this.setValue(value);
40334 setCurrency : function(v)
40336 this.currencyValue = v;
40339 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40344 setValue : function(v)
40346 v = this.fixPrecision(v);
40348 v = String(v).replace(".", this.decimalSeparator);
40353 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40358 getRawValue : function()
40360 var v = this.inputEl().getValue();
40365 getValue : function()
40367 return this.fixPrecision(this.parseValue(this.getRawValue()));
40370 parseValue : function(value)
40372 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40373 return isNaN(value) ? '' : value;
40376 fixPrecision : function(value)
40378 var nan = isNaN(value);
40380 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40381 return nan ? '' : value;
40384 return parseFloat(value).toFixed(this.decimalPrecision);
40387 decimalPrecisionFcn : function(v)
40389 return Math.floor(v);
40392 validateValue : function(value)
40394 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40398 var num = this.parseValue(value);
40401 this.markInvalid(String.format(this.nanText, value));
40405 if(num < this.minValue){
40406 this.markInvalid(String.format(this.minText, this.minValue));
40410 if(num > this.maxValue){
40411 this.markInvalid(String.format(this.maxText, this.maxValue));
40418 validate : function()
40420 if(this.disabled || this.allowBlank){
40425 var currency = this.getCurrency();
40427 if(this.validateValue(this.getRawValue()) && currency.length){
40432 this.markInvalid();
40436 getName: function()
40441 beforeBlur : function()
40447 var v = this.parseValue(this.getRawValue());
40454 onBlur : function()
40458 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40459 //this.el.removeClass(this.focusClass);
40462 this.hasFocus = false;
40464 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40468 var v = this.getValue();
40470 if(String(v) !== String(this.startValue)){
40471 this.fireEvent('change', this, v, this.startValue);
40474 this.fireEvent("blur", this);
40477 inputEl : function()
40479 return this.el.select('.roo-money-amount-input', true).first();
40482 currencyEl : function()
40484 return this.el.select('.roo-money-currency-input', true).first();