4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 cn.render && cn.render(this[cntr](true));
313 // then add the element..
321 if (typeof (tree.menu) != 'undefined') {
322 tree.menu.parentType = cn.xtype;
323 tree.menu.triggerEl = cn.el;
324 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
328 if (!tree.items || !tree.items.length) {
330 //Roo.log(["no children", this]);
335 var items = tree.items;
338 //Roo.log(items.length);
340 if (!skip_children) {
341 for(var i =0;i < items.length;i++) {
342 // Roo.log(['add child', items[i]]);
343 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
349 //Roo.log("fire childrenrendered");
351 cn.fireEvent('childrenrendered', this);
356 * Show a component - removes 'hidden' class
361 this.el.removeClass('hidden');
365 * Hide a component - adds 'hidden' class
369 if (this.el && !this.el.hasClass('hidden')) {
370 this.el.addClass('hidden');
383 * @class Roo.bootstrap.Body
384 * @extends Roo.bootstrap.Component
385 * Bootstrap Body class
389 * @param {Object} config The config object
392 Roo.bootstrap.Body = function(config){
394 config = config || {};
396 Roo.bootstrap.Body.superclass.constructor.call(this, config);
397 this.el = Roo.get(config.el ? config.el : document.body );
398 if (this.cls && this.cls.length) {
399 Roo.get(document.body).addClass(this.cls);
403 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
405 is_body : true,// just to make sure it's constructed?
410 onRender : function(ct, position)
412 /* Roo.log("Roo.bootstrap.Body - onRender");
413 if (this.cls && this.cls.length) {
414 Roo.get(document.body).addClass(this.cls);
433 * @class Roo.bootstrap.ButtonGroup
434 * @extends Roo.bootstrap.Component
435 * Bootstrap ButtonGroup class
436 * @cfg {String} size lg | sm | xs (default empty normal)
437 * @cfg {String} align vertical | justified (default none)
438 * @cfg {String} direction up | down (default down)
439 * @cfg {Boolean} toolbar false | true
440 * @cfg {Boolean} btn true | false
445 * @param {Object} config The config object
448 Roo.bootstrap.ButtonGroup = function(config){
449 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
452 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
460 getAutoCreate : function(){
466 cfg.html = this.html || cfg.html;
477 if (['vertical','justified'].indexOf(this.align)!==-1) {
478 cfg.cls = 'btn-group-' + this.align;
480 if (this.align == 'justified') {
481 console.log(this.items);
485 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
486 cfg.cls += ' btn-group-' + this.size;
489 if (this.direction == 'up') {
490 cfg.cls += ' dropup' ;
506 * @class Roo.bootstrap.Button
507 * @extends Roo.bootstrap.Component
508 * Bootstrap Button class
509 * @cfg {String} html The button content
510 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
511 * @cfg {String} size ( lg | sm | xs)
512 * @cfg {String} tag ( a | input | submit)
513 * @cfg {String} href empty or href
514 * @cfg {Boolean} disabled default false;
515 * @cfg {Boolean} isClose default false;
516 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
517 * @cfg {String} badge text for badge
518 * @cfg {String} theme default
519 * @cfg {Boolean} inverse
520 * @cfg {Boolean} toggle
521 * @cfg {String} ontext text for on toggle state
522 * @cfg {String} offtext text for off toggle state
523 * @cfg {Boolean} defaulton
524 * @cfg {Boolean} preventDefault default true
525 * @cfg {Boolean} removeClass remove the standard class..
526 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
529 * Create a new button
530 * @param {Object} config The config object
534 Roo.bootstrap.Button = function(config){
535 Roo.bootstrap.Button.superclass.constructor.call(this, config);
536 this.weightClass = ["btn-default",
548 * When a butotn is pressed
549 * @param {Roo.bootstrap.Button} this
550 * @param {Roo.EventObject} e
555 * After the button has been toggles
556 * @param {Roo.EventObject} e
557 * @param {boolean} pressed (also available as button.pressed)
563 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
581 preventDefault: true,
590 getAutoCreate : function(){
598 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
599 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
604 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
606 if (this.toggle == true) {
609 cls: 'slider-frame roo-button',
614 'data-off-text':'OFF',
615 cls: 'slider-button',
621 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
622 cfg.cls += ' '+this.weight;
631 cfg["aria-hidden"] = true;
633 cfg.html = "×";
639 if (this.theme==='default') {
640 cfg.cls = 'btn roo-button';
642 //if (this.parentType != 'Navbar') {
643 this.weight = this.weight.length ? this.weight : 'default';
645 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
647 cfg.cls += ' btn-' + this.weight;
649 } else if (this.theme==='glow') {
652 cfg.cls = 'btn-glow roo-button';
654 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
656 cfg.cls += ' ' + this.weight;
662 this.cls += ' inverse';
667 cfg.cls += ' active';
671 cfg.disabled = 'disabled';
675 Roo.log('changing to ul' );
677 this.glyphicon = 'caret';
680 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
682 //gsRoo.log(this.parentType);
683 if (this.parentType === 'Navbar' && !this.parent().bar) {
684 Roo.log('changing to li?');
693 href : this.href || '#'
696 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
697 cfg.cls += ' dropdown';
704 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
706 if (this.glyphicon) {
707 cfg.html = ' ' + cfg.html;
712 cls: 'glyphicon glyphicon-' + this.glyphicon
722 // cfg.cls='btn roo-button';
726 var value = cfg.html;
731 cls: 'glyphicon glyphicon-' + this.glyphicon,
750 cfg.cls += ' dropdown';
751 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
754 if (cfg.tag !== 'a' && this.href !== '') {
755 throw "Tag must be a to set href.";
756 } else if (this.href.length > 0) {
757 cfg.href = this.href;
760 if(this.removeClass){
765 cfg.target = this.target;
770 initEvents: function() {
771 // Roo.log('init events?');
772 // Roo.log(this.el.dom);
775 if (typeof (this.menu) != 'undefined') {
776 this.menu.parentType = this.xtype;
777 this.menu.triggerEl = this.el;
778 this.addxtype(Roo.apply({}, this.menu));
782 if (this.el.hasClass('roo-button')) {
783 this.el.on('click', this.onClick, this);
785 this.el.select('.roo-button').on('click', this.onClick, this);
788 if(this.removeClass){
789 this.el.on('click', this.onClick, this);
792 this.el.enableDisplayMode();
795 onClick : function(e)
802 Roo.log('button on click ');
803 if(this.preventDefault){
806 if (this.pressed === true || this.pressed === false) {
807 this.pressed = !this.pressed;
808 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
809 this.fireEvent('toggle', this, e, this.pressed);
813 this.fireEvent('click', this, e);
817 * Enables this button
821 this.disabled = false;
822 this.el.removeClass('disabled');
826 * Disable this button
830 this.disabled = true;
831 this.el.addClass('disabled');
834 * sets the active state on/off,
835 * @param {Boolean} state (optional) Force a particular state
837 setActive : function(v) {
839 this.el[v ? 'addClass' : 'removeClass']('active');
842 * toggles the current active state
844 toggleActive : function()
846 var active = this.el.hasClass('active');
847 this.setActive(!active);
851 setText : function(str)
853 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
857 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
868 setWeight : function(str)
870 this.el.removeClass(this.weightClass);
871 this.el.addClass('btn-' + str);
885 * @class Roo.bootstrap.Column
886 * @extends Roo.bootstrap.Component
887 * Bootstrap Column class
888 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
889 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
890 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
891 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
892 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
893 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
894 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
895 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
898 * @cfg {Boolean} hidden (true|false) hide the element
899 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
900 * @cfg {String} fa (ban|check|...) font awesome icon
901 * @cfg {Number} fasize (1|2|....) font awsome size
903 * @cfg {String} icon (info-sign|check|...) glyphicon name
905 * @cfg {String} html content of column.
908 * Create a new Column
909 * @param {Object} config The config object
912 Roo.bootstrap.Column = function(config){
913 Roo.bootstrap.Column.superclass.constructor.call(this, config);
916 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
934 getAutoCreate : function(){
935 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
943 ['xs','sm','md','lg'].map(function(size){
944 //Roo.log( size + ':' + settings[size]);
946 if (settings[size+'off'] !== false) {
947 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
950 if (settings[size] === false) {
954 if (!settings[size]) { // 0 = hidden
955 cfg.cls += ' hidden-' + size;
958 cfg.cls += ' col-' + size + '-' + settings[size];
963 cfg.cls += ' hidden';
966 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
967 cfg.cls +=' alert alert-' + this.alert;
971 if (this.html.length) {
972 cfg.html = this.html;
976 if (this.fasize > 1) {
977 fasize = ' fa-' + this.fasize + 'x';
979 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
984 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1003 * @class Roo.bootstrap.Container
1004 * @extends Roo.bootstrap.Component
1005 * Bootstrap Container class
1006 * @cfg {Boolean} jumbotron is it a jumbotron element
1007 * @cfg {String} html content of element
1008 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1009 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
1010 * @cfg {String} header content of header (for panel)
1011 * @cfg {String} footer content of footer (for panel)
1012 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1013 * @cfg {String} tag (header|aside|section) type of HTML tag.
1014 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1015 * @cfg {String} fa font awesome icon
1016 * @cfg {String} icon (info-sign|check|...) glyphicon name
1017 * @cfg {Boolean} hidden (true|false) hide the element
1018 * @cfg {Boolean} expandable (true|false) default false
1019 * @cfg {Boolean} expanded (true|false) default true
1020 * @cfg {String} rheader contet on the right of header
1021 * @cfg {Boolean} clickable (true|false) default false
1025 * Create a new Container
1026 * @param {Object} config The config object
1029 Roo.bootstrap.Container = function(config){
1030 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1036 * After the panel has been expand
1038 * @param {Roo.bootstrap.Container} this
1043 * After the panel has been collapsed
1045 * @param {Roo.bootstrap.Container} this
1050 * When a element is chick
1051 * @param {Roo.bootstrap.Container} this
1052 * @param {Roo.EventObject} e
1058 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1076 getChildContainer : function() {
1082 if (this.panel.length) {
1083 return this.el.select('.panel-body',true).first();
1090 getAutoCreate : function(){
1093 tag : this.tag || 'div',
1097 if (this.jumbotron) {
1098 cfg.cls = 'jumbotron';
1103 // - this is applied by the parent..
1105 // cfg.cls = this.cls + '';
1108 if (this.sticky.length) {
1110 var bd = Roo.get(document.body);
1111 if (!bd.hasClass('bootstrap-sticky')) {
1112 bd.addClass('bootstrap-sticky');
1113 Roo.select('html',true).setStyle('height', '100%');
1116 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1120 if (this.well.length) {
1121 switch (this.well) {
1124 cfg.cls +=' well well-' +this.well;
1133 cfg.cls += ' hidden';
1137 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1138 cfg.cls +=' alert alert-' + this.alert;
1143 if (this.panel.length) {
1144 cfg.cls += ' panel panel-' + this.panel;
1146 if (this.header.length) {
1150 if(this.expandable){
1152 cfg.cls = cfg.cls + ' expandable';
1156 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1164 cls : 'panel-title',
1165 html : (this.expandable ? ' ' : '') + this.header
1169 cls: 'panel-header-right',
1175 cls : 'panel-heading',
1176 style : this.expandable ? 'cursor: pointer' : '',
1184 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1189 if (this.footer.length) {
1191 cls : 'panel-footer',
1200 body.html = this.html || cfg.html;
1201 // prefix with the icons..
1203 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1206 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1211 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1212 cfg.cls = 'container';
1218 initEvents: function()
1220 if(this.expandable){
1221 var headerEl = this.headerEl();
1224 headerEl.on('click', this.onToggleClick, this);
1229 this.el.on('click', this.onClick, this);
1234 onToggleClick : function()
1236 var headerEl = this.headerEl();
1252 if(this.fireEvent('expand', this)) {
1254 this.expanded = true;
1256 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1258 this.el.select('.panel-body',true).first().removeClass('hide');
1260 var toggleEl = this.toggleEl();
1266 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1271 collapse : function()
1273 if(this.fireEvent('collapse', this)) {
1275 this.expanded = false;
1277 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1278 this.el.select('.panel-body',true).first().addClass('hide');
1280 var toggleEl = this.toggleEl();
1286 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1290 toggleEl : function()
1292 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1296 return this.el.select('.panel-heading .fa',true).first();
1299 headerEl : function()
1301 if(!this.el || !this.panel.length || !this.header.length){
1305 return this.el.select('.panel-heading',true).first()
1310 if(!this.el || !this.panel.length){
1314 return this.el.select('.panel-body',true).first()
1317 titleEl : function()
1319 if(!this.el || !this.panel.length || !this.header.length){
1323 return this.el.select('.panel-title',true).first();
1326 setTitle : function(v)
1328 var titleEl = this.titleEl();
1334 titleEl.dom.innerHTML = v;
1337 getTitle : function()
1340 var titleEl = this.titleEl();
1346 return titleEl.dom.innerHTML;
1349 setRightTitle : function(v)
1351 var t = this.el.select('.panel-header-right',true).first();
1357 t.dom.innerHTML = v;
1360 onClick : function(e)
1364 this.fireEvent('click', this, e);
1378 * @class Roo.bootstrap.Img
1379 * @extends Roo.bootstrap.Component
1380 * Bootstrap Img class
1381 * @cfg {Boolean} imgResponsive false | true
1382 * @cfg {String} border rounded | circle | thumbnail
1383 * @cfg {String} src image source
1384 * @cfg {String} alt image alternative text
1385 * @cfg {String} href a tag href
1386 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1387 * @cfg {String} xsUrl xs image source
1388 * @cfg {String} smUrl sm image source
1389 * @cfg {String} mdUrl md image source
1390 * @cfg {String} lgUrl lg image source
1393 * Create a new Input
1394 * @param {Object} config The config object
1397 Roo.bootstrap.Img = function(config){
1398 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1404 * The img click event for the img.
1405 * @param {Roo.EventObject} e
1411 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1413 imgResponsive: true,
1423 getAutoCreate : function()
1425 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1426 return this.createSingleImg();
1431 cls: 'roo-image-responsive-group',
1436 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1438 if(!_this[size + 'Url']){
1444 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1445 html: _this.html || cfg.html,
1446 src: _this[size + 'Url']
1449 img.cls += ' roo-image-responsive-' + size;
1451 var s = ['xs', 'sm', 'md', 'lg'];
1453 s.splice(s.indexOf(size), 1);
1455 Roo.each(s, function(ss){
1456 img.cls += ' hidden-' + ss;
1459 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1460 cfg.cls += ' img-' + _this.border;
1464 cfg.alt = _this.alt;
1477 a.target = _this.target;
1481 cfg.cn.push((_this.href) ? a : img);
1488 createSingleImg : function()
1492 cls: (this.imgResponsive) ? 'img-responsive' : '',
1494 src : 'about:blank' // just incase src get's set to undefined?!?
1497 cfg.html = this.html || cfg.html;
1499 cfg.src = this.src || cfg.src;
1501 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1502 cfg.cls += ' img-' + this.border;
1519 a.target = this.target;
1524 return (this.href) ? a : cfg;
1527 initEvents: function()
1530 this.el.on('click', this.onClick, this);
1535 onClick : function(e)
1537 Roo.log('img onclick');
1538 this.fireEvent('click', this, e);
1541 * Sets the url of the image - used to update it
1542 * @param {String} url the url of the image
1545 setSrc : function(url)
1549 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1550 this.el.dom.src = url;
1554 this.el.select('img', true).first().dom.src = url;
1570 * @class Roo.bootstrap.Link
1571 * @extends Roo.bootstrap.Component
1572 * Bootstrap Link Class
1573 * @cfg {String} alt image alternative text
1574 * @cfg {String} href a tag href
1575 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1576 * @cfg {String} html the content of the link.
1577 * @cfg {String} anchor name for the anchor link
1578 * @cfg {String} fa - favicon
1580 * @cfg {Boolean} preventDefault (true | false) default false
1584 * Create a new Input
1585 * @param {Object} config The config object
1588 Roo.bootstrap.Link = function(config){
1589 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1595 * The img click event for the img.
1596 * @param {Roo.EventObject} e
1602 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1606 preventDefault: false,
1612 getAutoCreate : function()
1614 var html = this.html || '';
1616 if (this.fa !== false) {
1617 html = '<i class="fa fa-' + this.fa + '"></i>';
1622 // anchor's do not require html/href...
1623 if (this.anchor === false) {
1625 cfg.href = this.href || '#';
1627 cfg.name = this.anchor;
1628 if (this.html !== false || this.fa !== false) {
1631 if (this.href !== false) {
1632 cfg.href = this.href;
1636 if(this.alt !== false){
1641 if(this.target !== false) {
1642 cfg.target = this.target;
1648 initEvents: function() {
1650 if(!this.href || this.preventDefault){
1651 this.el.on('click', this.onClick, this);
1655 onClick : function(e)
1657 if(this.preventDefault){
1660 //Roo.log('img onclick');
1661 this.fireEvent('click', this, e);
1674 * @class Roo.bootstrap.Header
1675 * @extends Roo.bootstrap.Component
1676 * Bootstrap Header class
1677 * @cfg {String} html content of header
1678 * @cfg {Number} level (1|2|3|4|5|6) default 1
1681 * Create a new Header
1682 * @param {Object} config The config object
1686 Roo.bootstrap.Header = function(config){
1687 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1690 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1698 getAutoCreate : function(){
1703 tag: 'h' + (1 *this.level),
1704 html: this.html || ''
1716 * Ext JS Library 1.1.1
1717 * Copyright(c) 2006-2007, Ext JS, LLC.
1719 * Originally Released Under LGPL - original licence link has changed is not relivant.
1722 * <script type="text/javascript">
1726 * @class Roo.bootstrap.MenuMgr
1727 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1730 Roo.bootstrap.MenuMgr = function(){
1731 var menus, active, groups = {}, attached = false, lastShow = new Date();
1733 // private - called when first menu is created
1736 active = new Roo.util.MixedCollection();
1737 Roo.get(document).addKeyListener(27, function(){
1738 if(active.length > 0){
1746 if(active && active.length > 0){
1747 var c = active.clone();
1757 if(active.length < 1){
1758 Roo.get(document).un("mouseup", onMouseDown);
1766 var last = active.last();
1767 lastShow = new Date();
1770 Roo.get(document).on("mouseup", onMouseDown);
1775 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1776 m.parentMenu.activeChild = m;
1777 }else if(last && last.isVisible()){
1778 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1783 function onBeforeHide(m){
1785 m.activeChild.hide();
1787 if(m.autoHideTimer){
1788 clearTimeout(m.autoHideTimer);
1789 delete m.autoHideTimer;
1794 function onBeforeShow(m){
1795 var pm = m.parentMenu;
1796 if(!pm && !m.allowOtherMenus){
1798 }else if(pm && pm.activeChild && active != m){
1799 pm.activeChild.hide();
1803 // private this should really trigger on mouseup..
1804 function onMouseDown(e){
1805 Roo.log("on Mouse Up");
1807 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1808 Roo.log("MenuManager hideAll");
1817 function onBeforeCheck(mi, state){
1819 var g = groups[mi.group];
1820 for(var i = 0, l = g.length; i < l; i++){
1822 g[i].setChecked(false);
1831 * Hides all menus that are currently visible
1833 hideAll : function(){
1838 register : function(menu){
1842 menus[menu.id] = menu;
1843 menu.on("beforehide", onBeforeHide);
1844 menu.on("hide", onHide);
1845 menu.on("beforeshow", onBeforeShow);
1846 menu.on("show", onShow);
1848 if(g && menu.events["checkchange"]){
1852 groups[g].push(menu);
1853 menu.on("checkchange", onCheck);
1858 * Returns a {@link Roo.menu.Menu} object
1859 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1860 * be used to generate and return a new Menu instance.
1862 get : function(menu){
1863 if(typeof menu == "string"){ // menu id
1865 }else if(menu.events){ // menu instance
1868 /*else if(typeof menu.length == 'number'){ // array of menu items?
1869 return new Roo.bootstrap.Menu({items:menu});
1870 }else{ // otherwise, must be a config
1871 return new Roo.bootstrap.Menu(menu);
1878 unregister : function(menu){
1879 delete menus[menu.id];
1880 menu.un("beforehide", onBeforeHide);
1881 menu.un("hide", onHide);
1882 menu.un("beforeshow", onBeforeShow);
1883 menu.un("show", onShow);
1885 if(g && menu.events["checkchange"]){
1886 groups[g].remove(menu);
1887 menu.un("checkchange", onCheck);
1892 registerCheckable : function(menuItem){
1893 var g = menuItem.group;
1898 groups[g].push(menuItem);
1899 menuItem.on("beforecheckchange", onBeforeCheck);
1904 unregisterCheckable : function(menuItem){
1905 var g = menuItem.group;
1907 groups[g].remove(menuItem);
1908 menuItem.un("beforecheckchange", onBeforeCheck);
1920 * @class Roo.bootstrap.Menu
1921 * @extends Roo.bootstrap.Component
1922 * Bootstrap Menu class - container for MenuItems
1923 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1924 * @cfg {bool} hidden if the menu should be hidden when rendered.
1925 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1926 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1930 * @param {Object} config The config object
1934 Roo.bootstrap.Menu = function(config){
1935 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1936 if (this.registerMenu && this.type != 'treeview') {
1937 Roo.bootstrap.MenuMgr.register(this);
1942 * Fires before this menu is displayed
1943 * @param {Roo.menu.Menu} this
1948 * Fires before this menu is hidden
1949 * @param {Roo.menu.Menu} this
1954 * Fires after this menu is displayed
1955 * @param {Roo.menu.Menu} this
1960 * Fires after this menu is hidden
1961 * @param {Roo.menu.Menu} this
1966 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1967 * @param {Roo.menu.Menu} this
1968 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1969 * @param {Roo.EventObject} e
1974 * Fires when the mouse is hovering over this menu
1975 * @param {Roo.menu.Menu} this
1976 * @param {Roo.EventObject} e
1977 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1982 * Fires when the mouse exits this menu
1983 * @param {Roo.menu.Menu} this
1984 * @param {Roo.EventObject} e
1985 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1990 * Fires when a menu item contained in this menu is clicked
1991 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1992 * @param {Roo.EventObject} e
1996 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1999 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2003 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2006 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2008 registerMenu : true,
2010 menuItems :false, // stores the menu items..
2020 getChildContainer : function() {
2024 getAutoCreate : function(){
2026 //if (['right'].indexOf(this.align)!==-1) {
2027 // cfg.cn[1].cls += ' pull-right'
2033 cls : 'dropdown-menu' ,
2034 style : 'z-index:1000'
2038 if (this.type === 'submenu') {
2039 cfg.cls = 'submenu active';
2041 if (this.type === 'treeview') {
2042 cfg.cls = 'treeview-menu';
2047 initEvents : function() {
2049 // Roo.log("ADD event");
2050 // Roo.log(this.triggerEl.dom);
2052 this.triggerEl.on('click', this.onTriggerClick, this);
2054 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2056 this.triggerEl.addClass('dropdown-toggle');
2059 this.el.on('touchstart' , this.onTouch, this);
2061 this.el.on('click' , this.onClick, this);
2063 this.el.on("mouseover", this.onMouseOver, this);
2064 this.el.on("mouseout", this.onMouseOut, this);
2068 findTargetItem : function(e)
2070 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2074 //Roo.log(t); Roo.log(t.id);
2076 //Roo.log(this.menuitems);
2077 return this.menuitems.get(t.id);
2079 //return this.items.get(t.menuItemId);
2085 onTouch : function(e)
2087 Roo.log("menu.onTouch");
2088 //e.stopEvent(); this make the user popdown broken
2092 onClick : function(e)
2094 Roo.log("menu.onClick");
2096 var t = this.findTargetItem(e);
2097 if(!t || t.isContainer){
2102 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2103 if(t == this.activeItem && t.shouldDeactivate(e)){
2104 this.activeItem.deactivate();
2105 delete this.activeItem;
2109 this.setActiveItem(t, true);
2117 Roo.log('pass click event');
2121 this.fireEvent("click", this, t, e);
2125 if(!t.href.length || t.href == '#'){
2126 (function() { _this.hide(); }).defer(100);
2131 onMouseOver : function(e){
2132 var t = this.findTargetItem(e);
2135 // if(t.canActivate && !t.disabled){
2136 // this.setActiveItem(t, true);
2140 this.fireEvent("mouseover", this, e, t);
2142 isVisible : function(){
2143 return !this.hidden;
2145 onMouseOut : function(e){
2146 var t = this.findTargetItem(e);
2149 // if(t == this.activeItem && t.shouldDeactivate(e)){
2150 // this.activeItem.deactivate();
2151 // delete this.activeItem;
2154 this.fireEvent("mouseout", this, e, t);
2159 * Displays this menu relative to another element
2160 * @param {String/HTMLElement/Roo.Element} element The element to align to
2161 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2162 * the element (defaults to this.defaultAlign)
2163 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2165 show : function(el, pos, parentMenu){
2166 this.parentMenu = parentMenu;
2170 this.fireEvent("beforeshow", this);
2171 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2174 * Displays this menu at a specific xy position
2175 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2176 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2178 showAt : function(xy, parentMenu, /* private: */_e){
2179 this.parentMenu = parentMenu;
2184 this.fireEvent("beforeshow", this);
2185 //xy = this.el.adjustForConstraints(xy);
2189 this.hideMenuItems();
2190 this.hidden = false;
2191 this.triggerEl.addClass('open');
2193 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2194 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2197 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2202 this.fireEvent("show", this);
2208 this.doFocus.defer(50, this);
2212 doFocus : function(){
2214 this.focusEl.focus();
2219 * Hides this menu and optionally all parent menus
2220 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2222 hide : function(deep)
2225 this.hideMenuItems();
2226 if(this.el && this.isVisible()){
2227 this.fireEvent("beforehide", this);
2228 if(this.activeItem){
2229 this.activeItem.deactivate();
2230 this.activeItem = null;
2232 this.triggerEl.removeClass('open');;
2234 this.fireEvent("hide", this);
2236 if(deep === true && this.parentMenu){
2237 this.parentMenu.hide(true);
2241 onTriggerClick : function(e)
2243 Roo.log('trigger click');
2245 var target = e.getTarget();
2247 Roo.log(target.nodeName.toLowerCase());
2249 if(target.nodeName.toLowerCase() === 'i'){
2255 onTriggerPress : function(e)
2257 Roo.log('trigger press');
2258 //Roo.log(e.getTarget());
2259 // Roo.log(this.triggerEl.dom);
2261 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2262 var pel = Roo.get(e.getTarget());
2263 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2264 Roo.log('is treeview or dropdown?');
2268 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2272 if (this.isVisible()) {
2277 this.show(this.triggerEl, false, false);
2280 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2287 hideMenuItems : function()
2289 Roo.log("hide Menu Items");
2293 //$(backdrop).remove()
2294 this.el.select('.open',true).each(function(aa) {
2296 aa.removeClass('open');
2297 //var parent = getParent($(this))
2298 //var relatedTarget = { relatedTarget: this }
2300 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2301 //if (e.isDefaultPrevented()) return
2302 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2305 addxtypeChild : function (tree, cntr) {
2306 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2308 this.menuitems.add(comp);
2329 * @class Roo.bootstrap.MenuItem
2330 * @extends Roo.bootstrap.Component
2331 * Bootstrap MenuItem class
2332 * @cfg {String} html the menu label
2333 * @cfg {String} href the link
2334 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2335 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2336 * @cfg {Boolean} active used on sidebars to highlight active itesm
2337 * @cfg {String} fa favicon to show on left of menu item.
2338 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2342 * Create a new MenuItem
2343 * @param {Object} config The config object
2347 Roo.bootstrap.MenuItem = function(config){
2348 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2353 * The raw click event for the entire grid.
2354 * @param {Roo.bootstrap.MenuItem} this
2355 * @param {Roo.EventObject} e
2361 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2365 preventDefault: false,
2366 isContainer : false,
2370 getAutoCreate : function(){
2372 if(this.isContainer){
2375 cls: 'dropdown-menu-item'
2389 if (this.fa !== false) {
2392 cls : 'fa fa-' + this.fa
2401 cls: 'dropdown-menu-item',
2404 if (this.parent().type == 'treeview') {
2405 cfg.cls = 'treeview-menu';
2408 cfg.cls += ' active';
2413 anc.href = this.href || cfg.cn[0].href ;
2414 ctag.html = this.html || cfg.cn[0].html ;
2418 initEvents: function()
2420 if (this.parent().type == 'treeview') {
2421 this.el.select('a').on('click', this.onClick, this);
2425 this.menu.parentType = this.xtype;
2426 this.menu.triggerEl = this.el;
2427 this.menu = this.addxtype(Roo.apply({}, this.menu));
2431 onClick : function(e)
2433 Roo.log('item on click ');
2435 if(this.preventDefault){
2438 //this.parent().hideMenuItems();
2440 this.fireEvent('click', this, e);
2459 * @class Roo.bootstrap.MenuSeparator
2460 * @extends Roo.bootstrap.Component
2461 * Bootstrap MenuSeparator class
2464 * Create a new MenuItem
2465 * @param {Object} config The config object
2469 Roo.bootstrap.MenuSeparator = function(config){
2470 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2473 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2475 getAutoCreate : function(){
2494 * @class Roo.bootstrap.Modal
2495 * @extends Roo.bootstrap.Component
2496 * Bootstrap Modal class
2497 * @cfg {String} title Title of dialog
2498 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2499 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2500 * @cfg {Boolean} specificTitle default false
2501 * @cfg {Array} buttons Array of buttons or standard button set..
2502 * @cfg {String} buttonPosition (left|right|center) default right
2503 * @cfg {Boolean} animate default true
2504 * @cfg {Boolean} allow_close default true
2505 * @cfg {Boolean} fitwindow default false
2506 * @cfg {String} size (sm|lg) default empty
2510 * Create a new Modal Dialog
2511 * @param {Object} config The config object
2514 Roo.bootstrap.Modal = function(config){
2515 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2520 * The raw btnclick event for the button
2521 * @param {Roo.EventObject} e
2526 * Fire when dialog resize
2527 * @param {Roo.bootstrap.Modal} this
2528 * @param {Roo.EventObject} e
2532 this.buttons = this.buttons || [];
2535 this.tmpl = Roo.factory(this.tmpl);
2540 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2542 title : 'test dialog',
2552 specificTitle: false,
2554 buttonPosition: 'right',
2573 onRender : function(ct, position)
2575 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2578 var cfg = Roo.apply({}, this.getAutoCreate());
2581 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2583 //if (!cfg.name.length) {
2587 cfg.cls += ' ' + this.cls;
2590 cfg.style = this.style;
2592 this.el = Roo.get(document.body).createChild(cfg, position);
2594 //var type = this.el.dom.type;
2597 if(this.tabIndex !== undefined){
2598 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2601 this.dialogEl = this.el.select('.modal-dialog',true).first();
2602 this.bodyEl = this.el.select('.modal-body',true).first();
2603 this.closeEl = this.el.select('.modal-header .close', true).first();
2604 this.headerEl = this.el.select('.modal-header',true).first();
2605 this.titleEl = this.el.select('.modal-title',true).first();
2606 this.footerEl = this.el.select('.modal-footer',true).first();
2608 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2609 this.maskEl.enableDisplayMode("block");
2611 //this.el.addClass("x-dlg-modal");
2613 if (this.buttons.length) {
2614 Roo.each(this.buttons, function(bb) {
2615 var b = Roo.apply({}, bb);
2616 b.xns = b.xns || Roo.bootstrap;
2617 b.xtype = b.xtype || 'Button';
2618 if (typeof(b.listeners) == 'undefined') {
2619 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2622 var btn = Roo.factory(b);
2624 btn.render(this.el.select('.modal-footer div').first());
2628 // render the children.
2631 if(typeof(this.items) != 'undefined'){
2632 var items = this.items;
2635 for(var i =0;i < items.length;i++) {
2636 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2640 this.items = nitems;
2642 // where are these used - they used to be body/close/footer
2646 //this.el.addClass([this.fieldClass, this.cls]);
2650 getAutoCreate : function(){
2655 html : this.html || ''
2660 cls : 'modal-title',
2664 if(this.specificTitle){
2670 if (this.allow_close) {
2682 if(this.size.length){
2683 size = 'modal-' + this.size;
2688 style : 'display: none',
2691 cls: "modal-dialog " + size,
2694 cls : "modal-content",
2697 cls : 'modal-header',
2702 cls : 'modal-footer',
2706 cls: 'btn-' + this.buttonPosition
2723 modal.cls += ' fade';
2729 getChildContainer : function() {
2734 getButtonContainer : function() {
2735 return this.el.select('.modal-footer div',true).first();
2738 initEvents : function()
2740 if (this.allow_close) {
2741 this.closeEl.on('click', this.hide, this);
2743 Roo.EventManager.onWindowResize(this.resize, this, true);
2750 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2751 if (this.fitwindow) {
2752 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2753 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2758 setSize : function(w,h)
2768 if (!this.rendered) {
2772 this.el.setStyle('display', 'block');
2774 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2777 this.el.addClass('in');
2780 this.el.addClass('in');
2784 // not sure how we can show data in here..
2786 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2789 Roo.get(document.body).addClass("x-body-masked");
2791 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2792 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2797 this.fireEvent('show', this);
2799 // set zindex here - otherwise it appears to be ignored...
2800 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2803 this.items.forEach( function(e) {
2804 e.layout ? e.layout() : false;
2812 if(this.fireEvent("beforehide", this) !== false){
2814 Roo.get(document.body).removeClass("x-body-masked");
2815 this.el.removeClass('in');
2816 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2818 if(this.animate){ // why
2820 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2822 this.el.setStyle('display', 'none');
2824 this.fireEvent('hide', this);
2828 addButton : function(str, cb)
2832 var b = Roo.apply({}, { html : str } );
2833 b.xns = b.xns || Roo.bootstrap;
2834 b.xtype = b.xtype || 'Button';
2835 if (typeof(b.listeners) == 'undefined') {
2836 b.listeners = { click : cb.createDelegate(this) };
2839 var btn = Roo.factory(b);
2841 btn.render(this.el.select('.modal-footer div').first());
2847 setDefaultButton : function(btn)
2849 //this.el.select('.modal-footer').()
2853 resizeTo: function(w,h)
2857 this.dialogEl.setWidth(w);
2858 if (this.diff === false) {
2859 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2862 this.bodyEl.setHeight(h-this.diff);
2864 this.fireEvent('resize', this);
2867 setContentSize : function(w, h)
2871 onButtonClick: function(btn,e)
2874 this.fireEvent('btnclick', btn.name, e);
2877 * Set the title of the Dialog
2878 * @param {String} str new Title
2880 setTitle: function(str) {
2881 this.titleEl.dom.innerHTML = str;
2884 * Set the body of the Dialog
2885 * @param {String} str new Title
2887 setBody: function(str) {
2888 this.bodyEl.dom.innerHTML = str;
2891 * Set the body of the Dialog using the template
2892 * @param {Obj} data - apply this data to the template and replace the body contents.
2894 applyBody: function(obj)
2897 Roo.log("Error - using apply Body without a template");
2900 this.tmpl.overwrite(this.bodyEl, obj);
2906 Roo.apply(Roo.bootstrap.Modal, {
2908 * Button config that displays a single OK button
2917 * Button config that displays Yes and No buttons
2933 * Button config that displays OK and Cancel buttons
2948 * Button config that displays Yes, No and Cancel buttons
2972 * messagebox - can be used as a replace
2976 * @class Roo.MessageBox
2977 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2981 Roo.Msg.alert('Status', 'Changes saved successfully.');
2983 // Prompt for user data:
2984 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2986 // process text value...
2990 // Show a dialog using config options:
2992 title:'Save Changes?',
2993 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2994 buttons: Roo.Msg.YESNOCANCEL,
3001 Roo.bootstrap.MessageBox = function(){
3002 var dlg, opt, mask, waitTimer;
3003 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3004 var buttons, activeTextEl, bwidth;
3008 var handleButton = function(button){
3010 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3014 var handleHide = function(){
3016 dlg.el.removeClass(opt.cls);
3019 // Roo.TaskMgr.stop(waitTimer);
3020 // waitTimer = null;
3025 var updateButtons = function(b){
3028 buttons["ok"].hide();
3029 buttons["cancel"].hide();
3030 buttons["yes"].hide();
3031 buttons["no"].hide();
3032 //dlg.footer.dom.style.display = 'none';
3035 dlg.footerEl.dom.style.display = '';
3036 for(var k in buttons){
3037 if(typeof buttons[k] != "function"){
3040 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3041 width += buttons[k].el.getWidth()+15;
3051 var handleEsc = function(d, k, e){
3052 if(opt && opt.closable !== false){
3062 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3063 * @return {Roo.BasicDialog} The BasicDialog element
3065 getDialog : function(){
3067 dlg = new Roo.bootstrap.Modal( {
3070 //constraintoviewport:false,
3072 //collapsible : false,
3077 //buttonAlign:"center",
3078 closeClick : function(){
3079 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3082 handleButton("cancel");
3087 dlg.on("hide", handleHide);
3089 //dlg.addKeyListener(27, handleEsc);
3091 this.buttons = buttons;
3092 var bt = this.buttonText;
3093 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3094 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3095 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3096 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3098 bodyEl = dlg.bodyEl.createChild({
3100 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3101 '<textarea class="roo-mb-textarea"></textarea>' +
3102 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3104 msgEl = bodyEl.dom.firstChild;
3105 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3106 textboxEl.enableDisplayMode();
3107 textboxEl.addKeyListener([10,13], function(){
3108 if(dlg.isVisible() && opt && opt.buttons){
3111 }else if(opt.buttons.yes){
3112 handleButton("yes");
3116 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3117 textareaEl.enableDisplayMode();
3118 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3119 progressEl.enableDisplayMode();
3121 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3122 //var pf = progressEl.dom.firstChild;
3124 //pp = Roo.get(pf.firstChild);
3125 //pp.setHeight(pf.offsetHeight);
3133 * Updates the message box body text
3134 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3135 * the XHTML-compliant non-breaking space character '&#160;')
3136 * @return {Roo.MessageBox} This message box
3138 updateText : function(text)
3140 if(!dlg.isVisible() && !opt.width){
3141 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3142 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3144 msgEl.innerHTML = text || ' ';
3146 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3147 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3149 Math.min(opt.width || cw , this.maxWidth),
3150 Math.max(opt.minWidth || this.minWidth, bwidth)
3153 activeTextEl.setWidth(w);
3155 if(dlg.isVisible()){
3156 dlg.fixedcenter = false;
3158 // to big, make it scroll. = But as usual stupid IE does not support
3161 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3162 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3163 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3165 bodyEl.dom.style.height = '';
3166 bodyEl.dom.style.overflowY = '';
3169 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3171 bodyEl.dom.style.overflowX = '';
3174 dlg.setContentSize(w, bodyEl.getHeight());
3175 if(dlg.isVisible()){
3176 dlg.fixedcenter = true;
3182 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3183 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3184 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3185 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3186 * @return {Roo.MessageBox} This message box
3188 updateProgress : function(value, text){
3190 this.updateText(text);
3192 if (pp) { // weird bug on my firefox - for some reason this is not defined
3193 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3199 * Returns true if the message box is currently displayed
3200 * @return {Boolean} True if the message box is visible, else false
3202 isVisible : function(){
3203 return dlg && dlg.isVisible();
3207 * Hides the message box if it is displayed
3210 if(this.isVisible()){
3216 * Displays a new message box, or reinitializes an existing message box, based on the config options
3217 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3218 * The following config object properties are supported:
3220 Property Type Description
3221 ---------- --------------- ------------------------------------------------------------------------------------
3222 animEl String/Element An id or Element from which the message box should animate as it opens and
3223 closes (defaults to undefined)
3224 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3225 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3226 closable Boolean False to hide the top-right close button (defaults to true). Note that
3227 progress and wait dialogs will ignore this property and always hide the
3228 close button as they can only be closed programmatically.
3229 cls String A custom CSS class to apply to the message box element
3230 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3231 displayed (defaults to 75)
3232 fn Function A callback function to execute after closing the dialog. The arguments to the
3233 function will be btn (the name of the button that was clicked, if applicable,
3234 e.g. "ok"), and text (the value of the active text field, if applicable).
3235 Progress and wait dialogs will ignore this option since they do not respond to
3236 user actions and can only be closed programmatically, so any required function
3237 should be called by the same code after it closes the dialog.
3238 icon String A CSS class that provides a background image to be used as an icon for
3239 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3240 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3241 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3242 modal Boolean False to allow user interaction with the page while the message box is
3243 displayed (defaults to true)
3244 msg String A string that will replace the existing message box body text (defaults
3245 to the XHTML-compliant non-breaking space character ' ')
3246 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3247 progress Boolean True to display a progress bar (defaults to false)
3248 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3249 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3250 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3251 title String The title text
3252 value String The string value to set into the active textbox element if displayed
3253 wait Boolean True to display a progress bar (defaults to false)
3254 width Number The width of the dialog in pixels
3261 msg: 'Please enter your address:',
3263 buttons: Roo.MessageBox.OKCANCEL,
3266 animEl: 'addAddressBtn'
3269 * @param {Object} config Configuration options
3270 * @return {Roo.MessageBox} This message box
3272 show : function(options)
3275 // this causes nightmares if you show one dialog after another
3276 // especially on callbacks..
3278 if(this.isVisible()){
3281 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3282 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3283 Roo.log("New Dialog Message:" + options.msg )
3284 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3285 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3288 var d = this.getDialog();
3290 d.setTitle(opt.title || " ");
3291 d.closeEl.setDisplayed(opt.closable !== false);
3292 activeTextEl = textboxEl;
3293 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3298 textareaEl.setHeight(typeof opt.multiline == "number" ?
3299 opt.multiline : this.defaultTextHeight);
3300 activeTextEl = textareaEl;
3309 progressEl.setDisplayed(opt.progress === true);
3310 this.updateProgress(0);
3311 activeTextEl.dom.value = opt.value || "";
3313 dlg.setDefaultButton(activeTextEl);
3315 var bs = opt.buttons;
3319 }else if(bs && bs.yes){
3320 db = buttons["yes"];
3322 dlg.setDefaultButton(db);
3324 bwidth = updateButtons(opt.buttons);
3325 this.updateText(opt.msg);
3327 d.el.addClass(opt.cls);
3329 d.proxyDrag = opt.proxyDrag === true;
3330 d.modal = opt.modal !== false;
3331 d.mask = opt.modal !== false ? mask : false;
3333 // force it to the end of the z-index stack so it gets a cursor in FF
3334 document.body.appendChild(dlg.el.dom);
3335 d.animateTarget = null;
3336 d.show(options.animEl);
3342 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3343 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3344 * and closing the message box when the process is complete.
3345 * @param {String} title The title bar text
3346 * @param {String} msg The message box body text
3347 * @return {Roo.MessageBox} This message box
3349 progress : function(title, msg){
3356 minWidth: this.minProgressWidth,
3363 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3364 * If a callback function is passed it will be called after the user clicks the button, and the
3365 * id of the button that was clicked will be passed as the only parameter to the callback
3366 * (could also be the top-right close button).
3367 * @param {String} title The title bar text
3368 * @param {String} msg The message box body text
3369 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3370 * @param {Object} scope (optional) The scope of the callback function
3371 * @return {Roo.MessageBox} This message box
3373 alert : function(title, msg, fn, scope)
3388 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3389 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3390 * You are responsible for closing the message box when the process is complete.
3391 * @param {String} msg The message box body text
3392 * @param {String} title (optional) The title bar text
3393 * @return {Roo.MessageBox} This message box
3395 wait : function(msg, title){
3406 waitTimer = Roo.TaskMgr.start({
3408 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3416 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3417 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3418 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3419 * @param {String} title The title bar text
3420 * @param {String} msg The message box body text
3421 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3422 * @param {Object} scope (optional) The scope of the callback function
3423 * @return {Roo.MessageBox} This message box
3425 confirm : function(title, msg, fn, scope){
3429 buttons: this.YESNO,
3438 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3439 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3440 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3441 * (could also be the top-right close button) and the text that was entered will be passed as the two
3442 * parameters to the callback.
3443 * @param {String} title The title bar text
3444 * @param {String} msg The message box body text
3445 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3446 * @param {Object} scope (optional) The scope of the callback function
3447 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3448 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3449 * @return {Roo.MessageBox} This message box
3451 prompt : function(title, msg, fn, scope, multiline){
3455 buttons: this.OKCANCEL,
3460 multiline: multiline,
3467 * Button config that displays a single OK button
3472 * Button config that displays Yes and No buttons
3475 YESNO : {yes:true, no:true},
3477 * Button config that displays OK and Cancel buttons
3480 OKCANCEL : {ok:true, cancel:true},
3482 * Button config that displays Yes, No and Cancel buttons
3485 YESNOCANCEL : {yes:true, no:true, cancel:true},
3488 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3491 defaultTextHeight : 75,
3493 * The maximum width in pixels of the message box (defaults to 600)
3498 * The minimum width in pixels of the message box (defaults to 100)
3503 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3504 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3507 minProgressWidth : 250,
3509 * An object containing the default button text strings that can be overriden for localized language support.
3510 * Supported properties are: ok, cancel, yes and no.
3511 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3524 * Shorthand for {@link Roo.MessageBox}
3526 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3527 Roo.Msg = Roo.Msg || Roo.MessageBox;
3536 * @class Roo.bootstrap.Navbar
3537 * @extends Roo.bootstrap.Component
3538 * Bootstrap Navbar class
3541 * Create a new Navbar
3542 * @param {Object} config The config object
3546 Roo.bootstrap.Navbar = function(config){
3547 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3551 * @event beforetoggle
3552 * Fire before toggle the menu
3553 * @param {Roo.EventObject} e
3555 "beforetoggle" : true
3559 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3568 getAutoCreate : function(){
3571 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3575 initEvents :function ()
3577 //Roo.log(this.el.select('.navbar-toggle',true));
3578 this.el.select('.navbar-toggle',true).on('click', function() {
3579 if(this.fireEvent('beforetoggle', this) !== false){
3580 this.el.select('.navbar-collapse',true).toggleClass('in');
3590 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3592 var size = this.el.getSize();
3593 this.maskEl.setSize(size.width, size.height);
3594 this.maskEl.enableDisplayMode("block");
3603 getChildContainer : function()
3605 if (this.el.select('.collapse').getCount()) {
3606 return this.el.select('.collapse',true).first();
3639 * @class Roo.bootstrap.NavSimplebar
3640 * @extends Roo.bootstrap.Navbar
3641 * Bootstrap Sidebar class
3643 * @cfg {Boolean} inverse is inverted color
3645 * @cfg {String} type (nav | pills | tabs)
3646 * @cfg {Boolean} arrangement stacked | justified
3647 * @cfg {String} align (left | right) alignment
3649 * @cfg {Boolean} main (true|false) main nav bar? default false
3650 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3652 * @cfg {String} tag (header|footer|nav|div) default is nav
3658 * Create a new Sidebar
3659 * @param {Object} config The config object
3663 Roo.bootstrap.NavSimplebar = function(config){
3664 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3667 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3683 getAutoCreate : function(){
3687 tag : this.tag || 'div',
3700 this.type = this.type || 'nav';
3701 if (['tabs','pills'].indexOf(this.type)!==-1) {
3702 cfg.cn[0].cls += ' nav-' + this.type
3706 if (this.type!=='nav') {
3707 Roo.log('nav type must be nav/tabs/pills')
3709 cfg.cn[0].cls += ' navbar-nav'
3715 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3716 cfg.cn[0].cls += ' nav-' + this.arrangement;
3720 if (this.align === 'right') {
3721 cfg.cn[0].cls += ' navbar-right';
3725 cfg.cls += ' navbar-inverse';
3752 * @class Roo.bootstrap.NavHeaderbar
3753 * @extends Roo.bootstrap.NavSimplebar
3754 * Bootstrap Sidebar class
3756 * @cfg {String} brand what is brand
3757 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3758 * @cfg {String} brand_href href of the brand
3759 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3760 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3761 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3762 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3765 * Create a new Sidebar
3766 * @param {Object} config The config object
3770 Roo.bootstrap.NavHeaderbar = function(config){
3771 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3775 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3782 desktopCenter : false,
3785 getAutoCreate : function(){
3788 tag: this.nav || 'nav',
3795 if (this.desktopCenter) {
3796 cn.push({cls : 'container', cn : []});
3803 cls: 'navbar-header',
3808 cls: 'navbar-toggle',
3809 'data-toggle': 'collapse',
3814 html: 'Toggle navigation'
3836 cls: 'collapse navbar-collapse',
3840 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3842 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3843 cfg.cls += ' navbar-' + this.position;
3845 // tag can override this..
3847 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3850 if (this.brand !== '') {
3853 href: this.brand_href ? this.brand_href : '#',
3854 cls: 'navbar-brand',
3862 cfg.cls += ' main-nav';
3870 getHeaderChildContainer : function()
3872 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3873 return this.el.select('.navbar-header',true).first();
3876 return this.getChildContainer();
3880 initEvents : function()
3882 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3884 if (this.autohide) {
3889 Roo.get(document).on('scroll',function(e) {
3890 var ns = Roo.get(document).getScroll().top;
3891 var os = prevScroll;
3895 ft.removeClass('slideDown');
3896 ft.addClass('slideUp');
3899 ft.removeClass('slideUp');
3900 ft.addClass('slideDown');
3921 * @class Roo.bootstrap.NavSidebar
3922 * @extends Roo.bootstrap.Navbar
3923 * Bootstrap Sidebar class
3926 * Create a new Sidebar
3927 * @param {Object} config The config object
3931 Roo.bootstrap.NavSidebar = function(config){
3932 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3935 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3937 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3939 getAutoCreate : function(){
3944 cls: 'sidebar sidebar-nav'
3966 * @class Roo.bootstrap.NavGroup
3967 * @extends Roo.bootstrap.Component
3968 * Bootstrap NavGroup class
3969 * @cfg {String} align (left|right)
3970 * @cfg {Boolean} inverse
3971 * @cfg {String} type (nav|pills|tab) default nav
3972 * @cfg {String} navId - reference Id for navbar.
3976 * Create a new nav group
3977 * @param {Object} config The config object
3980 Roo.bootstrap.NavGroup = function(config){
3981 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3984 Roo.bootstrap.NavGroup.register(this);
3988 * Fires when the active item changes
3989 * @param {Roo.bootstrap.NavGroup} this
3990 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3991 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3998 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4009 getAutoCreate : function()
4011 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4018 if (['tabs','pills'].indexOf(this.type)!==-1) {
4019 cfg.cls += ' nav-' + this.type
4021 if (this.type!=='nav') {
4022 Roo.log('nav type must be nav/tabs/pills')
4024 cfg.cls += ' navbar-nav'
4027 if (this.parent().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 * {bool} open is the menu open
4570 * Create a new Navbar Button
4571 * @param {Object} config The config object
4573 Roo.bootstrap.NavSidebarItem = function(config){
4574 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4579 * The raw click event for the entire grid.
4580 * @param {Roo.EventObject} e
4585 * Fires when the active item active state changes
4586 * @param {Roo.bootstrap.NavSidebarItem} this
4587 * @param {boolean} state the new state
4595 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4597 badgeWeight : 'default',
4601 getAutoCreate : function(){
4606 href : this.href || '#',
4618 html : this.html || ''
4623 cfg.cls += ' active';
4626 if (this.disabled) {
4627 cfg.cls += ' disabled';
4630 cfg.cls += ' open x-open';
4633 if (this.glyphicon || this.icon) {
4634 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4635 a.cn.push({ tag : 'i', cls : c }) ;
4640 if (this.badge !== '') {
4642 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4646 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4647 a.cls += 'dropdown-toggle treeview' ;
4655 initEvents : function()
4657 if (typeof (this.menu) != 'undefined') {
4658 this.menu.parentType = this.xtype;
4659 this.menu.triggerEl = this.el;
4660 this.menu = this.addxtype(Roo.apply({}, this.menu));
4663 this.el.on('click', this.onClick, this);
4666 if(this.badge !== ''){
4668 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4673 onClick : function(e)
4680 if(this.preventDefault){
4684 this.fireEvent('click', this);
4687 disable : function()
4689 this.setDisabled(true);
4694 this.setDisabled(false);
4697 setDisabled : function(state)
4699 if(this.disabled == state){
4703 this.disabled = state;
4706 this.el.addClass('disabled');
4710 this.el.removeClass('disabled');
4715 setActive : function(state)
4717 if(this.active == state){
4721 this.active = state;
4724 this.el.addClass('active');
4728 this.el.removeClass('active');
4733 isActive: function ()
4738 setBadge : function(str)
4744 this.badgeEl.dom.innerHTML = str;
4761 * @class Roo.bootstrap.Row
4762 * @extends Roo.bootstrap.Component
4763 * Bootstrap Row class (contains columns...)
4767 * @param {Object} config The config object
4770 Roo.bootstrap.Row = function(config){
4771 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4774 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4776 getAutoCreate : function(){
4795 * @class Roo.bootstrap.Element
4796 * @extends Roo.bootstrap.Component
4797 * Bootstrap Element class
4798 * @cfg {String} html contents of the element
4799 * @cfg {String} tag tag of the element
4800 * @cfg {String} cls class of the element
4801 * @cfg {Boolean} preventDefault (true|false) default false
4802 * @cfg {Boolean} clickable (true|false) default false
4805 * Create a new Element
4806 * @param {Object} config The config object
4809 Roo.bootstrap.Element = function(config){
4810 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4816 * When a element is chick
4817 * @param {Roo.bootstrap.Element} this
4818 * @param {Roo.EventObject} e
4824 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4829 preventDefault: false,
4832 getAutoCreate : function(){
4843 initEvents: function()
4845 Roo.bootstrap.Element.superclass.initEvents.call(this);
4848 this.el.on('click', this.onClick, this);
4853 onClick : function(e)
4855 if(this.preventDefault){
4859 this.fireEvent('click', this, e);
4862 getValue : function()
4864 return this.el.dom.innerHTML;
4867 setValue : function(value)
4869 this.el.dom.innerHTML = value;
4884 * @class Roo.bootstrap.Pagination
4885 * @extends Roo.bootstrap.Component
4886 * Bootstrap Pagination class
4887 * @cfg {String} size xs | sm | md | lg
4888 * @cfg {Boolean} inverse false | true
4891 * Create a new Pagination
4892 * @param {Object} config The config object
4895 Roo.bootstrap.Pagination = function(config){
4896 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4899 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4905 getAutoCreate : function(){
4911 cfg.cls += ' inverse';
4917 cfg.cls += " " + this.cls;
4935 * @class Roo.bootstrap.PaginationItem
4936 * @extends Roo.bootstrap.Component
4937 * Bootstrap PaginationItem class
4938 * @cfg {String} html text
4939 * @cfg {String} href the link
4940 * @cfg {Boolean} preventDefault (true | false) default true
4941 * @cfg {Boolean} active (true | false) default false
4942 * @cfg {Boolean} disabled default false
4946 * Create a new PaginationItem
4947 * @param {Object} config The config object
4951 Roo.bootstrap.PaginationItem = function(config){
4952 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4957 * The raw click event for the entire grid.
4958 * @param {Roo.EventObject} e
4964 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4968 preventDefault: true,
4973 getAutoCreate : function(){
4979 href : this.href ? this.href : '#',
4980 html : this.html ? this.html : ''
4990 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4994 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5000 initEvents: function() {
5002 this.el.on('click', this.onClick, this);
5005 onClick : function(e)
5007 Roo.log('PaginationItem on click ');
5008 if(this.preventDefault){
5016 this.fireEvent('click', this, e);
5032 * @class Roo.bootstrap.Slider
5033 * @extends Roo.bootstrap.Component
5034 * Bootstrap Slider class
5037 * Create a new Slider
5038 * @param {Object} config The config object
5041 Roo.bootstrap.Slider = function(config){
5042 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5045 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5047 getAutoCreate : function(){
5051 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5055 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5067 * Ext JS Library 1.1.1
5068 * Copyright(c) 2006-2007, Ext JS, LLC.
5070 * Originally Released Under LGPL - original licence link has changed is not relivant.
5073 * <script type="text/javascript">
5078 * @class Roo.grid.ColumnModel
5079 * @extends Roo.util.Observable
5080 * This is the default implementation of a ColumnModel used by the Grid. It defines
5081 * the columns in the grid.
5084 var colModel = new Roo.grid.ColumnModel([
5085 {header: "Ticker", width: 60, sortable: true, locked: true},
5086 {header: "Company Name", width: 150, sortable: true},
5087 {header: "Market Cap.", width: 100, sortable: true},
5088 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5089 {header: "Employees", width: 100, sortable: true, resizable: false}
5094 * The config options listed for this class are options which may appear in each
5095 * individual column definition.
5096 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5098 * @param {Object} config An Array of column config objects. See this class's
5099 * config objects for details.
5101 Roo.grid.ColumnModel = function(config){
5103 * The config passed into the constructor
5105 this.config = config;
5108 // if no id, create one
5109 // if the column does not have a dataIndex mapping,
5110 // map it to the order it is in the config
5111 for(var i = 0, len = config.length; i < len; i++){
5113 if(typeof c.dataIndex == "undefined"){
5116 if(typeof c.renderer == "string"){
5117 c.renderer = Roo.util.Format[c.renderer];
5119 if(typeof c.id == "undefined"){
5122 if(c.editor && c.editor.xtype){
5123 c.editor = Roo.factory(c.editor, Roo.grid);
5125 if(c.editor && c.editor.isFormField){
5126 c.editor = new Roo.grid.GridEditor(c.editor);
5128 this.lookup[c.id] = c;
5132 * The width of columns which have no width specified (defaults to 100)
5135 this.defaultWidth = 100;
5138 * Default sortable of columns which have no sortable specified (defaults to false)
5141 this.defaultSortable = false;
5145 * @event widthchange
5146 * Fires when the width of a column changes.
5147 * @param {ColumnModel} this
5148 * @param {Number} columnIndex The column index
5149 * @param {Number} newWidth The new width
5151 "widthchange": true,
5153 * @event headerchange
5154 * Fires when the text of a header changes.
5155 * @param {ColumnModel} this
5156 * @param {Number} columnIndex The column index
5157 * @param {Number} newText The new header text
5159 "headerchange": true,
5161 * @event hiddenchange
5162 * Fires when a column is hidden or "unhidden".
5163 * @param {ColumnModel} this
5164 * @param {Number} columnIndex The column index
5165 * @param {Boolean} hidden true if hidden, false otherwise
5167 "hiddenchange": true,
5169 * @event columnmoved
5170 * Fires when a column is moved.
5171 * @param {ColumnModel} this
5172 * @param {Number} oldIndex
5173 * @param {Number} newIndex
5175 "columnmoved" : true,
5177 * @event columlockchange
5178 * Fires when a column's locked state is changed
5179 * @param {ColumnModel} this
5180 * @param {Number} colIndex
5181 * @param {Boolean} locked true if locked
5183 "columnlockchange" : true
5185 Roo.grid.ColumnModel.superclass.constructor.call(this);
5187 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5189 * @cfg {String} header The header text to display in the Grid view.
5192 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5193 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5194 * specified, the column's index is used as an index into the Record's data Array.
5197 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5198 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5201 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5202 * Defaults to the value of the {@link #defaultSortable} property.
5203 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5206 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5209 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5212 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5215 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5218 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5219 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5220 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5221 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5224 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5227 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5230 * @cfg {String} cursor (Optional)
5233 * @cfg {String} tooltip (Optional)
5236 * @cfg {Number} xs (Optional)
5239 * @cfg {Number} sm (Optional)
5242 * @cfg {Number} md (Optional)
5245 * @cfg {Number} lg (Optional)
5248 * Returns the id of the column at the specified index.
5249 * @param {Number} index The column index
5250 * @return {String} the id
5252 getColumnId : function(index){
5253 return this.config[index].id;
5257 * Returns the column for a specified id.
5258 * @param {String} id The column id
5259 * @return {Object} the column
5261 getColumnById : function(id){
5262 return this.lookup[id];
5267 * Returns the column for a specified dataIndex.
5268 * @param {String} dataIndex The column dataIndex
5269 * @return {Object|Boolean} the column or false if not found
5271 getColumnByDataIndex: function(dataIndex){
5272 var index = this.findColumnIndex(dataIndex);
5273 return index > -1 ? this.config[index] : false;
5277 * Returns the index for a specified column id.
5278 * @param {String} id The column id
5279 * @return {Number} the index, or -1 if not found
5281 getIndexById : function(id){
5282 for(var i = 0, len = this.config.length; i < len; i++){
5283 if(this.config[i].id == id){
5291 * Returns the index for a specified column dataIndex.
5292 * @param {String} dataIndex The column dataIndex
5293 * @return {Number} the index, or -1 if not found
5296 findColumnIndex : function(dataIndex){
5297 for(var i = 0, len = this.config.length; i < len; i++){
5298 if(this.config[i].dataIndex == dataIndex){
5306 moveColumn : function(oldIndex, newIndex){
5307 var c = this.config[oldIndex];
5308 this.config.splice(oldIndex, 1);
5309 this.config.splice(newIndex, 0, c);
5310 this.dataMap = null;
5311 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5314 isLocked : function(colIndex){
5315 return this.config[colIndex].locked === true;
5318 setLocked : function(colIndex, value, suppressEvent){
5319 if(this.isLocked(colIndex) == value){
5322 this.config[colIndex].locked = value;
5324 this.fireEvent("columnlockchange", this, colIndex, value);
5328 getTotalLockedWidth : function(){
5330 for(var i = 0; i < this.config.length; i++){
5331 if(this.isLocked(i) && !this.isHidden(i)){
5332 this.totalWidth += this.getColumnWidth(i);
5338 getLockedCount : function(){
5339 for(var i = 0, len = this.config.length; i < len; i++){
5340 if(!this.isLocked(i)){
5345 return this.config.length;
5349 * Returns the number of columns.
5352 getColumnCount : function(visibleOnly){
5353 if(visibleOnly === true){
5355 for(var i = 0, len = this.config.length; i < len; i++){
5356 if(!this.isHidden(i)){
5362 return this.config.length;
5366 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5367 * @param {Function} fn
5368 * @param {Object} scope (optional)
5369 * @return {Array} result
5371 getColumnsBy : function(fn, scope){
5373 for(var i = 0, len = this.config.length; i < len; i++){
5374 var c = this.config[i];
5375 if(fn.call(scope||this, c, i) === true){
5383 * Returns true if the specified column is sortable.
5384 * @param {Number} col The column index
5387 isSortable : function(col){
5388 if(typeof this.config[col].sortable == "undefined"){
5389 return this.defaultSortable;
5391 return this.config[col].sortable;
5395 * Returns the rendering (formatting) function defined for the column.
5396 * @param {Number} col The column index.
5397 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5399 getRenderer : function(col){
5400 if(!this.config[col].renderer){
5401 return Roo.grid.ColumnModel.defaultRenderer;
5403 return this.config[col].renderer;
5407 * Sets the rendering (formatting) function for a column.
5408 * @param {Number} col The column index
5409 * @param {Function} fn The function to use to process the cell's raw data
5410 * to return HTML markup for the grid view. The render function is called with
5411 * the following parameters:<ul>
5412 * <li>Data value.</li>
5413 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5414 * <li>css A CSS style string to apply to the table cell.</li>
5415 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5416 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5417 * <li>Row index</li>
5418 * <li>Column index</li>
5419 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5421 setRenderer : function(col, fn){
5422 this.config[col].renderer = fn;
5426 * Returns the width for the specified column.
5427 * @param {Number} col The column index
5430 getColumnWidth : function(col){
5431 return this.config[col].width * 1 || this.defaultWidth;
5435 * Sets the width for a column.
5436 * @param {Number} col The column index
5437 * @param {Number} width The new width
5439 setColumnWidth : function(col, width, suppressEvent){
5440 this.config[col].width = width;
5441 this.totalWidth = null;
5443 this.fireEvent("widthchange", this, col, width);
5448 * Returns the total width of all columns.
5449 * @param {Boolean} includeHidden True to include hidden column widths
5452 getTotalWidth : function(includeHidden){
5453 if(!this.totalWidth){
5454 this.totalWidth = 0;
5455 for(var i = 0, len = this.config.length; i < len; i++){
5456 if(includeHidden || !this.isHidden(i)){
5457 this.totalWidth += this.getColumnWidth(i);
5461 return this.totalWidth;
5465 * Returns the header for the specified column.
5466 * @param {Number} col The column index
5469 getColumnHeader : function(col){
5470 return this.config[col].header;
5474 * Sets the header for a column.
5475 * @param {Number} col The column index
5476 * @param {String} header The new header
5478 setColumnHeader : function(col, header){
5479 this.config[col].header = header;
5480 this.fireEvent("headerchange", this, col, header);
5484 * Returns the tooltip for the specified column.
5485 * @param {Number} col The column index
5488 getColumnTooltip : function(col){
5489 return this.config[col].tooltip;
5492 * Sets the tooltip for a column.
5493 * @param {Number} col The column index
5494 * @param {String} tooltip The new tooltip
5496 setColumnTooltip : function(col, tooltip){
5497 this.config[col].tooltip = tooltip;
5501 * Returns the dataIndex for the specified column.
5502 * @param {Number} col The column index
5505 getDataIndex : function(col){
5506 return this.config[col].dataIndex;
5510 * Sets the dataIndex for a column.
5511 * @param {Number} col The column index
5512 * @param {Number} dataIndex The new dataIndex
5514 setDataIndex : function(col, dataIndex){
5515 this.config[col].dataIndex = dataIndex;
5521 * Returns true if the cell is editable.
5522 * @param {Number} colIndex The column index
5523 * @param {Number} rowIndex The row index - this is nto actually used..?
5526 isCellEditable : function(colIndex, rowIndex){
5527 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5531 * Returns the editor defined for the cell/column.
5532 * return false or null to disable editing.
5533 * @param {Number} colIndex The column index
5534 * @param {Number} rowIndex The row index
5537 getCellEditor : function(colIndex, rowIndex){
5538 return this.config[colIndex].editor;
5542 * Sets if a column is editable.
5543 * @param {Number} col The column index
5544 * @param {Boolean} editable True if the column is editable
5546 setEditable : function(col, editable){
5547 this.config[col].editable = editable;
5552 * Returns true if the column is hidden.
5553 * @param {Number} colIndex The column index
5556 isHidden : function(colIndex){
5557 return this.config[colIndex].hidden;
5562 * Returns true if the column width cannot be changed
5564 isFixed : function(colIndex){
5565 return this.config[colIndex].fixed;
5569 * Returns true if the column can be resized
5572 isResizable : function(colIndex){
5573 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5576 * Sets if a column is hidden.
5577 * @param {Number} colIndex The column index
5578 * @param {Boolean} hidden True if the column is hidden
5580 setHidden : function(colIndex, hidden){
5581 this.config[colIndex].hidden = hidden;
5582 this.totalWidth = null;
5583 this.fireEvent("hiddenchange", this, colIndex, hidden);
5587 * Sets the editor for a column.
5588 * @param {Number} col The column index
5589 * @param {Object} editor The editor object
5591 setEditor : function(col, editor){
5592 this.config[col].editor = editor;
5596 Roo.grid.ColumnModel.defaultRenderer = function(value)
5598 if(typeof value == "object") {
5601 if(typeof value == "string" && value.length < 1){
5605 return String.format("{0}", value);
5608 // Alias for backwards compatibility
5609 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5612 * Ext JS Library 1.1.1
5613 * Copyright(c) 2006-2007, Ext JS, LLC.
5615 * Originally Released Under LGPL - original licence link has changed is not relivant.
5618 * <script type="text/javascript">
5622 * @class Roo.LoadMask
5623 * A simple utility class for generically masking elements while loading data. If the element being masked has
5624 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5625 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5626 * element's UpdateManager load indicator and will be destroyed after the initial load.
5628 * Create a new LoadMask
5629 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5630 * @param {Object} config The config object
5632 Roo.LoadMask = function(el, config){
5633 this.el = Roo.get(el);
5634 Roo.apply(this, config);
5636 this.store.on('beforeload', this.onBeforeLoad, this);
5637 this.store.on('load', this.onLoad, this);
5638 this.store.on('loadexception', this.onLoadException, this);
5639 this.removeMask = false;
5641 var um = this.el.getUpdateManager();
5642 um.showLoadIndicator = false; // disable the default indicator
5643 um.on('beforeupdate', this.onBeforeLoad, this);
5644 um.on('update', this.onLoad, this);
5645 um.on('failure', this.onLoad, this);
5646 this.removeMask = true;
5650 Roo.LoadMask.prototype = {
5652 * @cfg {Boolean} removeMask
5653 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5654 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5658 * The text to display in a centered loading message box (defaults to 'Loading...')
5662 * @cfg {String} msgCls
5663 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5665 msgCls : 'x-mask-loading',
5668 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5674 * Disables the mask to prevent it from being displayed
5676 disable : function(){
5677 this.disabled = true;
5681 * Enables the mask so that it can be displayed
5683 enable : function(){
5684 this.disabled = false;
5687 onLoadException : function()
5691 if (typeof(arguments[3]) != 'undefined') {
5692 Roo.MessageBox.alert("Error loading",arguments[3]);
5696 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5697 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5704 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5709 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5713 onBeforeLoad : function(){
5715 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5720 destroy : function(){
5722 this.store.un('beforeload', this.onBeforeLoad, this);
5723 this.store.un('load', this.onLoad, this);
5724 this.store.un('loadexception', this.onLoadException, this);
5726 var um = this.el.getUpdateManager();
5727 um.un('beforeupdate', this.onBeforeLoad, this);
5728 um.un('update', this.onLoad, this);
5729 um.un('failure', this.onLoad, this);
5740 * @class Roo.bootstrap.Table
5741 * @extends Roo.bootstrap.Component
5742 * Bootstrap Table class
5743 * @cfg {String} cls table class
5744 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5745 * @cfg {String} bgcolor Specifies the background color for a table
5746 * @cfg {Number} border Specifies whether the table cells should have borders or not
5747 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5748 * @cfg {Number} cellspacing Specifies the space between cells
5749 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5750 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5751 * @cfg {String} sortable Specifies that the table should be sortable
5752 * @cfg {String} summary Specifies a summary of the content of a table
5753 * @cfg {Number} width Specifies the width of a table
5754 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5756 * @cfg {boolean} striped Should the rows be alternative striped
5757 * @cfg {boolean} bordered Add borders to the table
5758 * @cfg {boolean} hover Add hover highlighting
5759 * @cfg {boolean} condensed Format condensed
5760 * @cfg {boolean} responsive Format condensed
5761 * @cfg {Boolean} loadMask (true|false) default false
5762 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5763 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5764 * @cfg {Boolean} rowSelection (true|false) default false
5765 * @cfg {Boolean} cellSelection (true|false) default false
5766 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5767 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5768 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5772 * Create a new Table
5773 * @param {Object} config The config object
5776 Roo.bootstrap.Table = function(config){
5777 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5782 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5783 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5784 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5785 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5787 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5789 this.sm.grid = this;
5790 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5791 this.sm = this.selModel;
5792 this.sm.xmodule = this.xmodule || false;
5795 if (this.cm && typeof(this.cm.config) == 'undefined') {
5796 this.colModel = new Roo.grid.ColumnModel(this.cm);
5797 this.cm = this.colModel;
5798 this.cm.xmodule = this.xmodule || false;
5801 this.store= Roo.factory(this.store, Roo.data);
5802 this.ds = this.store;
5803 this.ds.xmodule = this.xmodule || false;
5806 if (this.footer && this.store) {
5807 this.footer.dataSource = this.ds;
5808 this.footer = Roo.factory(this.footer);
5815 * Fires when a cell is clicked
5816 * @param {Roo.bootstrap.Table} this
5817 * @param {Roo.Element} el
5818 * @param {Number} rowIndex
5819 * @param {Number} columnIndex
5820 * @param {Roo.EventObject} e
5824 * @event celldblclick
5825 * Fires when a cell is double clicked
5826 * @param {Roo.bootstrap.Table} this
5827 * @param {Roo.Element} el
5828 * @param {Number} rowIndex
5829 * @param {Number} columnIndex
5830 * @param {Roo.EventObject} e
5832 "celldblclick" : true,
5835 * Fires when a row is clicked
5836 * @param {Roo.bootstrap.Table} this
5837 * @param {Roo.Element} el
5838 * @param {Number} rowIndex
5839 * @param {Roo.EventObject} e
5843 * @event rowdblclick
5844 * Fires when a row is double clicked
5845 * @param {Roo.bootstrap.Table} this
5846 * @param {Roo.Element} el
5847 * @param {Number} rowIndex
5848 * @param {Roo.EventObject} e
5850 "rowdblclick" : true,
5853 * Fires when a mouseover occur
5854 * @param {Roo.bootstrap.Table} this
5855 * @param {Roo.Element} el
5856 * @param {Number} rowIndex
5857 * @param {Number} columnIndex
5858 * @param {Roo.EventObject} e
5863 * Fires when a mouseout occur
5864 * @param {Roo.bootstrap.Table} this
5865 * @param {Roo.Element} el
5866 * @param {Number} rowIndex
5867 * @param {Number} columnIndex
5868 * @param {Roo.EventObject} e
5873 * Fires when a row is rendered, so you can change add a style to it.
5874 * @param {Roo.bootstrap.Table} this
5875 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5879 * @event rowsrendered
5880 * Fires when all the rows have been rendered
5881 * @param {Roo.bootstrap.Table} this
5883 'rowsrendered' : true,
5885 * @event contextmenu
5886 * The raw contextmenu event for the entire grid.
5887 * @param {Roo.EventObject} e
5889 "contextmenu" : true,
5891 * @event rowcontextmenu
5892 * Fires when a row is right clicked
5893 * @param {Roo.bootstrap.Table} this
5894 * @param {Number} rowIndex
5895 * @param {Roo.EventObject} e
5897 "rowcontextmenu" : true,
5899 * @event cellcontextmenu
5900 * Fires when a cell is right clicked
5901 * @param {Roo.bootstrap.Table} this
5902 * @param {Number} rowIndex
5903 * @param {Number} cellIndex
5904 * @param {Roo.EventObject} e
5906 "cellcontextmenu" : true,
5908 * @event headercontextmenu
5909 * Fires when a header is right clicked
5910 * @param {Roo.bootstrap.Table} this
5911 * @param {Number} columnIndex
5912 * @param {Roo.EventObject} e
5914 "headercontextmenu" : true
5918 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5944 rowSelection : false,
5945 cellSelection : false,
5948 // Roo.Element - the tbody
5950 // Roo.Element - thead element
5953 container: false, // used by gridpanel...
5957 getAutoCreate : function()
5959 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5966 if (this.scrollBody) {
5967 cfg.cls += ' table-body-fixed';
5970 cfg.cls += ' table-striped';
5974 cfg.cls += ' table-hover';
5976 if (this.bordered) {
5977 cfg.cls += ' table-bordered';
5979 if (this.condensed) {
5980 cfg.cls += ' table-condensed';
5982 if (this.responsive) {
5983 cfg.cls += ' table-responsive';
5987 cfg.cls+= ' ' +this.cls;
5990 // this lot should be simplifed...
5993 cfg.align=this.align;
5996 cfg.bgcolor=this.bgcolor;
5999 cfg.border=this.border;
6001 if (this.cellpadding) {
6002 cfg.cellpadding=this.cellpadding;
6004 if (this.cellspacing) {
6005 cfg.cellspacing=this.cellspacing;
6008 cfg.frame=this.frame;
6011 cfg.rules=this.rules;
6013 if (this.sortable) {
6014 cfg.sortable=this.sortable;
6017 cfg.summary=this.summary;
6020 cfg.width=this.width;
6023 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6026 if(this.store || this.cm){
6027 if(this.headerShow){
6028 cfg.cn.push(this.renderHeader());
6031 cfg.cn.push(this.renderBody());
6033 if(this.footerShow){
6034 cfg.cn.push(this.renderFooter());
6036 // where does this come from?
6037 //cfg.cls+= ' TableGrid';
6040 return { cn : [ cfg ] };
6043 initEvents : function()
6045 if(!this.store || !this.cm){
6048 if (this.selModel) {
6049 this.selModel.initEvents();
6053 //Roo.log('initEvents with ds!!!!');
6055 this.mainBody = this.el.select('tbody', true).first();
6056 this.mainHead = this.el.select('thead', true).first();
6063 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6064 e.on('click', _this.sort, _this);
6067 this.mainBody.on("click", this.onClick, this);
6068 this.mainBody.on("dblclick", this.onDblClick, this);
6070 // why is this done????? = it breaks dialogs??
6071 //this.parent().el.setStyle('position', 'relative');
6075 this.footer.parentId = this.id;
6076 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6079 this.el.select('tfoot tr td').first().addClass('hide');
6083 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6085 this.store.on('load', this.onLoad, this);
6086 this.store.on('beforeload', this.onBeforeLoad, this);
6087 this.store.on('update', this.onUpdate, this);
6088 this.store.on('add', this.onAdd, this);
6089 this.store.on("clear", this.clear, this);
6091 this.el.on("contextmenu", this.onContextMenu, this);
6093 this.mainBody.on('scroll', this.onBodyScroll, this);
6098 onContextMenu : function(e, t)
6100 this.processEvent("contextmenu", e);
6103 processEvent : function(name, e)
6105 if (name != 'touchstart' ) {
6106 this.fireEvent(name, e);
6109 var t = e.getTarget();
6111 var cell = Roo.get(t);
6117 if(cell.findParent('tfoot', false, true)){
6121 if(cell.findParent('thead', false, true)){
6123 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6124 cell = Roo.get(t).findParent('th', false, true);
6126 Roo.log("failed to find th in thead?");
6127 Roo.log(e.getTarget());
6132 var cellIndex = cell.dom.cellIndex;
6134 var ename = name == 'touchstart' ? 'click' : name;
6135 this.fireEvent("header" + ename, this, cellIndex, e);
6140 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6141 cell = Roo.get(t).findParent('td', false, true);
6143 Roo.log("failed to find th in tbody?");
6144 Roo.log(e.getTarget());
6149 var row = cell.findParent('tr', false, true);
6150 var cellIndex = cell.dom.cellIndex;
6151 var rowIndex = row.dom.rowIndex - 1;
6155 this.fireEvent("row" + name, this, rowIndex, e);
6159 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6165 onMouseover : function(e, el)
6167 var cell = Roo.get(el);
6173 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6174 cell = cell.findParent('td', false, true);
6177 var row = cell.findParent('tr', false, true);
6178 var cellIndex = cell.dom.cellIndex;
6179 var rowIndex = row.dom.rowIndex - 1; // start from 0
6181 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6185 onMouseout : function(e, el)
6187 var cell = Roo.get(el);
6193 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6194 cell = cell.findParent('td', false, true);
6197 var row = cell.findParent('tr', false, true);
6198 var cellIndex = cell.dom.cellIndex;
6199 var rowIndex = row.dom.rowIndex - 1; // start from 0
6201 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6205 onClick : function(e, el)
6207 var cell = Roo.get(el);
6209 if(!cell || (!this.cellSelection && !this.rowSelection)){
6213 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6214 cell = cell.findParent('td', false, true);
6217 if(!cell || typeof(cell) == 'undefined'){
6221 var row = cell.findParent('tr', false, true);
6223 if(!row || typeof(row) == 'undefined'){
6227 var cellIndex = cell.dom.cellIndex;
6228 var rowIndex = this.getRowIndex(row);
6230 // why??? - should these not be based on SelectionModel?
6231 if(this.cellSelection){
6232 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6235 if(this.rowSelection){
6236 this.fireEvent('rowclick', this, row, rowIndex, e);
6242 onDblClick : function(e,el)
6244 var cell = Roo.get(el);
6246 if(!cell || (!this.cellSelection && !this.rowSelection)){
6250 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6251 cell = cell.findParent('td', false, true);
6254 if(!cell || typeof(cell) == 'undefined'){
6258 var row = cell.findParent('tr', false, true);
6260 if(!row || typeof(row) == 'undefined'){
6264 var cellIndex = cell.dom.cellIndex;
6265 var rowIndex = this.getRowIndex(row);
6267 if(this.cellSelection){
6268 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6271 if(this.rowSelection){
6272 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6276 sort : function(e,el)
6278 var col = Roo.get(el);
6280 if(!col.hasClass('sortable')){
6284 var sort = col.attr('sort');
6287 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6291 this.store.sortInfo = {field : sort, direction : dir};
6294 Roo.log("calling footer first");
6295 this.footer.onClick('first');
6298 this.store.load({ params : { start : 0 } });
6302 renderHeader : function()
6310 this.totalWidth = 0;
6312 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6314 var config = cm.config[i];
6319 html: cm.getColumnHeader(i)
6324 if(typeof(config.sortable) != 'undefined' && config.sortable){
6326 c.html = '<i class="glyphicon"></i>' + c.html;
6329 if(typeof(config.lgHeader) != 'undefined'){
6330 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6333 if(typeof(config.mdHeader) != 'undefined'){
6334 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6337 if(typeof(config.smHeader) != 'undefined'){
6338 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6341 if(typeof(config.xsHeader) != 'undefined'){
6342 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6349 if(typeof(config.tooltip) != 'undefined'){
6350 c.tooltip = config.tooltip;
6353 if(typeof(config.colspan) != 'undefined'){
6354 c.colspan = config.colspan;
6357 if(typeof(config.hidden) != 'undefined' && config.hidden){
6358 c.style += ' display:none;';
6361 if(typeof(config.dataIndex) != 'undefined'){
6362 c.sort = config.dataIndex;
6367 if(typeof(config.align) != 'undefined' && config.align.length){
6368 c.style += ' text-align:' + config.align + ';';
6371 if(typeof(config.width) != 'undefined'){
6372 c.style += ' width:' + config.width + 'px;';
6373 this.totalWidth += config.width;
6375 this.totalWidth += 100; // assume minimum of 100 per column?
6378 if(typeof(config.cls) != 'undefined'){
6379 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6382 ['xs','sm','md','lg'].map(function(size){
6384 if(typeof(config[size]) == 'undefined'){
6388 if (!config[size]) { // 0 = hidden
6389 c.cls += ' hidden-' + size;
6393 c.cls += ' col-' + size + '-' + config[size];
6403 renderBody : function()
6413 colspan : this.cm.getColumnCount()
6423 renderFooter : function()
6433 colspan : this.cm.getColumnCount()
6447 // Roo.log('ds onload');
6452 var ds = this.store;
6454 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6455 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6456 if (_this.store.sortInfo) {
6458 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6459 e.select('i', true).addClass(['glyphicon-arrow-up']);
6462 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6463 e.select('i', true).addClass(['glyphicon-arrow-down']);
6468 var tbody = this.mainBody;
6470 if(ds.getCount() > 0){
6471 ds.data.each(function(d,rowIndex){
6472 var row = this.renderRow(cm, ds, rowIndex);
6474 tbody.createChild(row);
6478 if(row.cellObjects.length){
6479 Roo.each(row.cellObjects, function(r){
6480 _this.renderCellObject(r);
6487 Roo.each(this.el.select('tbody td', true).elements, function(e){
6488 e.on('mouseover', _this.onMouseover, _this);
6491 Roo.each(this.el.select('tbody td', true).elements, function(e){
6492 e.on('mouseout', _this.onMouseout, _this);
6494 this.fireEvent('rowsrendered', this);
6495 //if(this.loadMask){
6496 // this.maskEl.hide();
6503 onUpdate : function(ds,record)
6505 this.refreshRow(record);
6509 onRemove : function(ds, record, index, isUpdate){
6510 if(isUpdate !== true){
6511 this.fireEvent("beforerowremoved", this, index, record);
6513 var bt = this.mainBody.dom;
6515 var rows = this.el.select('tbody > tr', true).elements;
6517 if(typeof(rows[index]) != 'undefined'){
6518 bt.removeChild(rows[index].dom);
6521 // if(bt.rows[index]){
6522 // bt.removeChild(bt.rows[index]);
6525 if(isUpdate !== true){
6526 //this.stripeRows(index);
6527 //this.syncRowHeights(index, index);
6529 this.fireEvent("rowremoved", this, index, record);
6533 onAdd : function(ds, records, rowIndex)
6535 //Roo.log('on Add called');
6536 // - note this does not handle multiple adding very well..
6537 var bt = this.mainBody.dom;
6538 for (var i =0 ; i < records.length;i++) {
6539 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6540 //Roo.log(records[i]);
6541 //Roo.log(this.store.getAt(rowIndex+i));
6542 this.insertRow(this.store, rowIndex + i, false);
6549 refreshRow : function(record){
6550 var ds = this.store, index;
6551 if(typeof record == 'number'){
6553 record = ds.getAt(index);
6555 index = ds.indexOf(record);
6557 this.insertRow(ds, index, true);
6559 this.onRemove(ds, record, index+1, true);
6561 //this.syncRowHeights(index, index);
6563 this.fireEvent("rowupdated", this, index, record);
6566 insertRow : function(dm, rowIndex, isUpdate){
6569 this.fireEvent("beforerowsinserted", this, rowIndex);
6571 //var s = this.getScrollState();
6572 var row = this.renderRow(this.cm, this.store, rowIndex);
6573 // insert before rowIndex..
6574 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6578 if(row.cellObjects.length){
6579 Roo.each(row.cellObjects, function(r){
6580 _this.renderCellObject(r);
6585 this.fireEvent("rowsinserted", this, rowIndex);
6586 //this.syncRowHeights(firstRow, lastRow);
6587 //this.stripeRows(firstRow);
6594 getRowDom : function(rowIndex)
6596 var rows = this.el.select('tbody > tr', true).elements;
6598 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6601 // returns the object tree for a tr..
6604 renderRow : function(cm, ds, rowIndex)
6607 var d = ds.getAt(rowIndex);
6614 var cellObjects = [];
6616 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6617 var config = cm.config[i];
6619 var renderer = cm.getRenderer(i);
6623 if(typeof(renderer) !== 'undefined'){
6624 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6626 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6627 // and are rendered into the cells after the row is rendered - using the id for the element.
6629 if(typeof(value) === 'object'){
6639 rowIndex : rowIndex,
6644 this.fireEvent('rowclass', this, rowcfg);
6648 cls : rowcfg.rowClass,
6650 html: (typeof(value) === 'object') ? '' : value
6657 if(typeof(config.colspan) != 'undefined'){
6658 td.colspan = config.colspan;
6661 if(typeof(config.hidden) != 'undefined' && config.hidden){
6662 td.style += ' display:none;';
6665 if(typeof(config.align) != 'undefined' && config.align.length){
6666 td.style += ' text-align:' + config.align + ';';
6669 if(typeof(config.width) != 'undefined'){
6670 td.style += ' width:' + config.width + 'px;';
6673 if(typeof(config.cursor) != 'undefined'){
6674 td.style += ' cursor:' + config.cursor + ';';
6677 if(typeof(config.cls) != 'undefined'){
6678 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6681 ['xs','sm','md','lg'].map(function(size){
6683 if(typeof(config[size]) == 'undefined'){
6687 if (!config[size]) { // 0 = hidden
6688 td.cls += ' hidden-' + size;
6692 td.cls += ' col-' + size + '-' + config[size];
6700 row.cellObjects = cellObjects;
6708 onBeforeLoad : function()
6710 //Roo.log('ds onBeforeLoad');
6714 //if(this.loadMask){
6715 // this.maskEl.show();
6723 this.el.select('tbody', true).first().dom.innerHTML = '';
6726 * Show or hide a row.
6727 * @param {Number} rowIndex to show or hide
6728 * @param {Boolean} state hide
6730 setRowVisibility : function(rowIndex, state)
6732 var bt = this.mainBody.dom;
6734 var rows = this.el.select('tbody > tr', true).elements;
6736 if(typeof(rows[rowIndex]) == 'undefined'){
6739 rows[rowIndex].dom.style.display = state ? '' : 'none';
6743 getSelectionModel : function(){
6745 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6747 return this.selModel;
6750 * Render the Roo.bootstrap object from renderder
6752 renderCellObject : function(r)
6756 var t = r.cfg.render(r.container);
6759 Roo.each(r.cfg.cn, function(c){
6761 container: t.getChildContainer(),
6764 _this.renderCellObject(child);
6769 getRowIndex : function(row)
6773 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6784 * Returns the grid's underlying element = used by panel.Grid
6785 * @return {Element} The element
6787 getGridEl : function(){
6791 * Forces a resize - used by panel.Grid
6792 * @return {Element} The element
6794 autoSize : function()
6796 //var ctr = Roo.get(this.container.dom.parentElement);
6797 var ctr = Roo.get(this.el.dom);
6799 var thd = this.getGridEl().select('thead',true).first();
6800 var tbd = this.getGridEl().select('tbody', true).first();
6801 var tfd = this.getGridEl().select('tfoot', true).first();
6803 var cw = ctr.getWidth();
6807 tbd.setSize(ctr.getWidth(),
6808 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6810 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6813 cw = Math.max(cw, this.totalWidth);
6814 this.getGridEl().select('tr',true).setWidth(cw);
6815 // resize 'expandable coloumn?
6817 return; // we doe not have a view in this design..
6820 onBodyScroll: function()
6822 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6823 this.mainHead.setStyle({
6824 'position' : 'relative',
6825 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6830 var scrollHeight = this.mainBody.dom.scrollHeight;
6832 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6834 var height = this.mainBody.getHeight();
6836 if(scrollHeight - height == scrollTop) {
6838 var total = this.ds.getTotalCount();
6840 if(this.footer.cursor + this.footer.pageSize < total){
6842 this.footer.ds.load({
6844 start : this.footer.cursor + this.footer.pageSize,
6845 limit : this.footer.pageSize
6866 * @class Roo.bootstrap.TableCell
6867 * @extends Roo.bootstrap.Component
6868 * Bootstrap TableCell class
6869 * @cfg {String} html cell contain text
6870 * @cfg {String} cls cell class
6871 * @cfg {String} tag cell tag (td|th) default td
6872 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6873 * @cfg {String} align Aligns the content in a cell
6874 * @cfg {String} axis Categorizes cells
6875 * @cfg {String} bgcolor Specifies the background color of a cell
6876 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6877 * @cfg {Number} colspan Specifies the number of columns a cell should span
6878 * @cfg {String} headers Specifies one or more header cells a cell is related to
6879 * @cfg {Number} height Sets the height of a cell
6880 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6881 * @cfg {Number} rowspan Sets the number of rows a cell should span
6882 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6883 * @cfg {String} valign Vertical aligns the content in a cell
6884 * @cfg {Number} width Specifies the width of a cell
6887 * Create a new TableCell
6888 * @param {Object} config The config object
6891 Roo.bootstrap.TableCell = function(config){
6892 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6895 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6915 getAutoCreate : function(){
6916 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6936 cfg.align=this.align
6942 cfg.bgcolor=this.bgcolor
6945 cfg.charoff=this.charoff
6948 cfg.colspan=this.colspan
6951 cfg.headers=this.headers
6954 cfg.height=this.height
6957 cfg.nowrap=this.nowrap
6960 cfg.rowspan=this.rowspan
6963 cfg.scope=this.scope
6966 cfg.valign=this.valign
6969 cfg.width=this.width
6988 * @class Roo.bootstrap.TableRow
6989 * @extends Roo.bootstrap.Component
6990 * Bootstrap TableRow class
6991 * @cfg {String} cls row class
6992 * @cfg {String} align Aligns the content in a table row
6993 * @cfg {String} bgcolor Specifies a background color for a table row
6994 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6995 * @cfg {String} valign Vertical aligns the content in a table row
6998 * Create a new TableRow
6999 * @param {Object} config The config object
7002 Roo.bootstrap.TableRow = function(config){
7003 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7006 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7014 getAutoCreate : function(){
7015 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7025 cfg.align = this.align;
7028 cfg.bgcolor = this.bgcolor;
7031 cfg.charoff = this.charoff;
7034 cfg.valign = this.valign;
7052 * @class Roo.bootstrap.TableBody
7053 * @extends Roo.bootstrap.Component
7054 * Bootstrap TableBody class
7055 * @cfg {String} cls element class
7056 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7057 * @cfg {String} align Aligns the content inside the element
7058 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7059 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7062 * Create a new TableBody
7063 * @param {Object} config The config object
7066 Roo.bootstrap.TableBody = function(config){
7067 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7070 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7078 getAutoCreate : function(){
7079 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7093 cfg.align = this.align;
7096 cfg.charoff = this.charoff;
7099 cfg.valign = this.valign;
7106 // initEvents : function()
7113 // this.store = Roo.factory(this.store, Roo.data);
7114 // this.store.on('load', this.onLoad, this);
7116 // this.store.load();
7120 // onLoad: function ()
7122 // this.fireEvent('load', this);
7132 * Ext JS Library 1.1.1
7133 * Copyright(c) 2006-2007, Ext JS, LLC.
7135 * Originally Released Under LGPL - original licence link has changed is not relivant.
7138 * <script type="text/javascript">
7141 // as we use this in bootstrap.
7142 Roo.namespace('Roo.form');
7144 * @class Roo.form.Action
7145 * Internal Class used to handle form actions
7147 * @param {Roo.form.BasicForm} el The form element or its id
7148 * @param {Object} config Configuration options
7153 // define the action interface
7154 Roo.form.Action = function(form, options){
7156 this.options = options || {};
7159 * Client Validation Failed
7162 Roo.form.Action.CLIENT_INVALID = 'client';
7164 * Server Validation Failed
7167 Roo.form.Action.SERVER_INVALID = 'server';
7169 * Connect to Server Failed
7172 Roo.form.Action.CONNECT_FAILURE = 'connect';
7174 * Reading Data from Server Failed
7177 Roo.form.Action.LOAD_FAILURE = 'load';
7179 Roo.form.Action.prototype = {
7181 failureType : undefined,
7182 response : undefined,
7186 run : function(options){
7191 success : function(response){
7196 handleResponse : function(response){
7200 // default connection failure
7201 failure : function(response){
7203 this.response = response;
7204 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7205 this.form.afterAction(this, false);
7208 processResponse : function(response){
7209 this.response = response;
7210 if(!response.responseText){
7213 this.result = this.handleResponse(response);
7217 // utility functions used internally
7218 getUrl : function(appendParams){
7219 var url = this.options.url || this.form.url || this.form.el.dom.action;
7221 var p = this.getParams();
7223 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7229 getMethod : function(){
7230 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7233 getParams : function(){
7234 var bp = this.form.baseParams;
7235 var p = this.options.params;
7237 if(typeof p == "object"){
7238 p = Roo.urlEncode(Roo.applyIf(p, bp));
7239 }else if(typeof p == 'string' && bp){
7240 p += '&' + Roo.urlEncode(bp);
7243 p = Roo.urlEncode(bp);
7248 createCallback : function(){
7250 success: this.success,
7251 failure: this.failure,
7253 timeout: (this.form.timeout*1000),
7254 upload: this.form.fileUpload ? this.success : undefined
7259 Roo.form.Action.Submit = function(form, options){
7260 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7263 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7266 haveProgress : false,
7267 uploadComplete : false,
7269 // uploadProgress indicator.
7270 uploadProgress : function()
7272 if (!this.form.progressUrl) {
7276 if (!this.haveProgress) {
7277 Roo.MessageBox.progress("Uploading", "Uploading");
7279 if (this.uploadComplete) {
7280 Roo.MessageBox.hide();
7284 this.haveProgress = true;
7286 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7288 var c = new Roo.data.Connection();
7290 url : this.form.progressUrl,
7295 success : function(req){
7296 //console.log(data);
7300 rdata = Roo.decode(req.responseText)
7302 Roo.log("Invalid data from server..");
7306 if (!rdata || !rdata.success) {
7308 Roo.MessageBox.alert(Roo.encode(rdata));
7311 var data = rdata.data;
7313 if (this.uploadComplete) {
7314 Roo.MessageBox.hide();
7319 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7320 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7323 this.uploadProgress.defer(2000,this);
7326 failure: function(data) {
7327 Roo.log('progress url failed ');
7338 // run get Values on the form, so it syncs any secondary forms.
7339 this.form.getValues();
7341 var o = this.options;
7342 var method = this.getMethod();
7343 var isPost = method == 'POST';
7344 if(o.clientValidation === false || this.form.isValid()){
7346 if (this.form.progressUrl) {
7347 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7348 (new Date() * 1) + '' + Math.random());
7353 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7354 form:this.form.el.dom,
7355 url:this.getUrl(!isPost),
7357 params:isPost ? this.getParams() : null,
7358 isUpload: this.form.fileUpload
7361 this.uploadProgress();
7363 }else if (o.clientValidation !== false){ // client validation failed
7364 this.failureType = Roo.form.Action.CLIENT_INVALID;
7365 this.form.afterAction(this, false);
7369 success : function(response)
7371 this.uploadComplete= true;
7372 if (this.haveProgress) {
7373 Roo.MessageBox.hide();
7377 var result = this.processResponse(response);
7378 if(result === true || result.success){
7379 this.form.afterAction(this, true);
7383 this.form.markInvalid(result.errors);
7384 this.failureType = Roo.form.Action.SERVER_INVALID;
7386 this.form.afterAction(this, false);
7388 failure : function(response)
7390 this.uploadComplete= true;
7391 if (this.haveProgress) {
7392 Roo.MessageBox.hide();
7395 this.response = response;
7396 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7397 this.form.afterAction(this, false);
7400 handleResponse : function(response){
7401 if(this.form.errorReader){
7402 var rs = this.form.errorReader.read(response);
7405 for(var i = 0, len = rs.records.length; i < len; i++) {
7406 var r = rs.records[i];
7410 if(errors.length < 1){
7414 success : rs.success,
7420 ret = Roo.decode(response.responseText);
7424 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7434 Roo.form.Action.Load = function(form, options){
7435 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7436 this.reader = this.form.reader;
7439 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7444 Roo.Ajax.request(Roo.apply(
7445 this.createCallback(), {
7446 method:this.getMethod(),
7447 url:this.getUrl(false),
7448 params:this.getParams()
7452 success : function(response){
7454 var result = this.processResponse(response);
7455 if(result === true || !result.success || !result.data){
7456 this.failureType = Roo.form.Action.LOAD_FAILURE;
7457 this.form.afterAction(this, false);
7460 this.form.clearInvalid();
7461 this.form.setValues(result.data);
7462 this.form.afterAction(this, true);
7465 handleResponse : function(response){
7466 if(this.form.reader){
7467 var rs = this.form.reader.read(response);
7468 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7470 success : rs.success,
7474 return Roo.decode(response.responseText);
7478 Roo.form.Action.ACTION_TYPES = {
7479 'load' : Roo.form.Action.Load,
7480 'submit' : Roo.form.Action.Submit
7489 * @class Roo.bootstrap.Form
7490 * @extends Roo.bootstrap.Component
7491 * Bootstrap Form class
7492 * @cfg {String} method GET | POST (default POST)
7493 * @cfg {String} labelAlign top | left (default top)
7494 * @cfg {String} align left | right - for navbars
7495 * @cfg {Boolean} loadMask load mask when submit (default true)
7500 * @param {Object} config The config object
7504 Roo.bootstrap.Form = function(config){
7505 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7507 Roo.bootstrap.Form.popover.apply();
7511 * @event clientvalidation
7512 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7513 * @param {Form} this
7514 * @param {Boolean} valid true if the form has passed client-side validation
7516 clientvalidation: true,
7518 * @event beforeaction
7519 * Fires before any action is performed. Return false to cancel the action.
7520 * @param {Form} this
7521 * @param {Action} action The action to be performed
7525 * @event actionfailed
7526 * Fires when an action fails.
7527 * @param {Form} this
7528 * @param {Action} action The action that failed
7530 actionfailed : true,
7532 * @event actioncomplete
7533 * Fires when an action is completed.
7534 * @param {Form} this
7535 * @param {Action} action The action that completed
7537 actioncomplete : true
7542 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7545 * @cfg {String} method
7546 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7551 * The URL to use for form actions if one isn't supplied in the action options.
7554 * @cfg {Boolean} fileUpload
7555 * Set to true if this form is a file upload.
7559 * @cfg {Object} baseParams
7560 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7564 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7568 * @cfg {Sting} align (left|right) for navbar forms
7573 activeAction : null,
7576 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7577 * element by passing it or its id or mask the form itself by passing in true.
7580 waitMsgTarget : false,
7585 * @cfg {Boolean} errorMask (true|false) default false
7590 * @cfg {Number} maskOffset Default 100
7594 getAutoCreate : function(){
7598 method : this.method || 'POST',
7599 id : this.id || Roo.id(),
7602 if (this.parent().xtype.match(/^Nav/)) {
7603 cfg.cls = 'navbar-form navbar-' + this.align;
7607 if (this.labelAlign == 'left' ) {
7608 cfg.cls += ' form-horizontal';
7614 initEvents : function()
7616 this.el.on('submit', this.onSubmit, this);
7617 // this was added as random key presses on the form where triggering form submit.
7618 this.el.on('keypress', function(e) {
7619 if (e.getCharCode() != 13) {
7622 // we might need to allow it for textareas.. and some other items.
7623 // check e.getTarget().
7625 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7629 Roo.log("keypress blocked");
7637 onSubmit : function(e){
7642 * Returns true if client-side validation on the form is successful.
7645 isValid : function(){
7646 var items = this.getItems();
7650 items.each(function(f){
7661 if(!target && f.el.isVisible(true)){
7667 if(this.errorMask && !valid){
7668 Roo.bootstrap.Form.popover.mask(this, target);
7675 * Returns true if any fields in this form have changed since their original load.
7678 isDirty : function(){
7680 var items = this.getItems();
7681 items.each(function(f){
7691 * Performs a predefined action (submit or load) or custom actions you define on this form.
7692 * @param {String} actionName The name of the action type
7693 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7694 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7695 * accept other config options):
7697 Property Type Description
7698 ---------------- --------------- ----------------------------------------------------------------------------------
7699 url String The url for the action (defaults to the form's url)
7700 method String The form method to use (defaults to the form's method, or POST if not defined)
7701 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7702 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7703 validate the form on the client (defaults to false)
7705 * @return {BasicForm} this
7707 doAction : function(action, options){
7708 if(typeof action == 'string'){
7709 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7711 if(this.fireEvent('beforeaction', this, action) !== false){
7712 this.beforeAction(action);
7713 action.run.defer(100, action);
7719 beforeAction : function(action){
7720 var o = action.options;
7723 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7725 // not really supported yet.. ??
7727 //if(this.waitMsgTarget === true){
7728 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7729 //}else if(this.waitMsgTarget){
7730 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7731 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7733 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7739 afterAction : function(action, success){
7740 this.activeAction = null;
7741 var o = action.options;
7743 //if(this.waitMsgTarget === true){
7745 //}else if(this.waitMsgTarget){
7746 // this.waitMsgTarget.unmask();
7748 // Roo.MessageBox.updateProgress(1);
7749 // Roo.MessageBox.hide();
7756 Roo.callback(o.success, o.scope, [this, action]);
7757 this.fireEvent('actioncomplete', this, action);
7761 // failure condition..
7762 // we have a scenario where updates need confirming.
7763 // eg. if a locking scenario exists..
7764 // we look for { errors : { needs_confirm : true }} in the response.
7766 (typeof(action.result) != 'undefined') &&
7767 (typeof(action.result.errors) != 'undefined') &&
7768 (typeof(action.result.errors.needs_confirm) != 'undefined')
7771 Roo.log("not supported yet");
7774 Roo.MessageBox.confirm(
7775 "Change requires confirmation",
7776 action.result.errorMsg,
7781 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7791 Roo.callback(o.failure, o.scope, [this, action]);
7792 // show an error message if no failed handler is set..
7793 if (!this.hasListener('actionfailed')) {
7794 Roo.log("need to add dialog support");
7796 Roo.MessageBox.alert("Error",
7797 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7798 action.result.errorMsg :
7799 "Saving Failed, please check your entries or try again"
7804 this.fireEvent('actionfailed', this, action);
7809 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7810 * @param {String} id The value to search for
7813 findField : function(id){
7814 var items = this.getItems();
7815 var field = items.get(id);
7817 items.each(function(f){
7818 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7825 return field || null;
7828 * Mark fields in this form invalid in bulk.
7829 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7830 * @return {BasicForm} this
7832 markInvalid : function(errors){
7833 if(errors instanceof Array){
7834 for(var i = 0, len = errors.length; i < len; i++){
7835 var fieldError = errors[i];
7836 var f = this.findField(fieldError.id);
7838 f.markInvalid(fieldError.msg);
7844 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7845 field.markInvalid(errors[id]);
7849 //Roo.each(this.childForms || [], function (f) {
7850 // f.markInvalid(errors);
7857 * Set values for fields in this form in bulk.
7858 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7859 * @return {BasicForm} this
7861 setValues : function(values){
7862 if(values instanceof Array){ // array of objects
7863 for(var i = 0, len = values.length; i < len; i++){
7865 var f = this.findField(v.id);
7867 f.setValue(v.value);
7868 if(this.trackResetOnLoad){
7869 f.originalValue = f.getValue();
7873 }else{ // object hash
7876 if(typeof values[id] != 'function' && (field = this.findField(id))){
7878 if (field.setFromData &&
7880 field.displayField &&
7881 // combos' with local stores can
7882 // be queried via setValue()
7883 // to set their value..
7884 (field.store && !field.store.isLocal)
7888 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7889 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7890 field.setFromData(sd);
7893 field.setValue(values[id]);
7897 if(this.trackResetOnLoad){
7898 field.originalValue = field.getValue();
7904 //Roo.each(this.childForms || [], function (f) {
7905 // f.setValues(values);
7912 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7913 * they are returned as an array.
7914 * @param {Boolean} asString
7917 getValues : function(asString){
7918 //if (this.childForms) {
7919 // copy values from the child forms
7920 // Roo.each(this.childForms, function (f) {
7921 // this.setValues(f.getValues());
7927 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7928 if(asString === true){
7931 return Roo.urlDecode(fs);
7935 * Returns the fields in this form as an object with key/value pairs.
7936 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7939 getFieldValues : function(with_hidden)
7941 var items = this.getItems();
7943 items.each(function(f){
7947 var v = f.getValue();
7948 if (f.inputType =='radio') {
7949 if (typeof(ret[f.getName()]) == 'undefined') {
7950 ret[f.getName()] = ''; // empty..
7953 if (!f.el.dom.checked) {
7961 // not sure if this supported any more..
7962 if ((typeof(v) == 'object') && f.getRawValue) {
7963 v = f.getRawValue() ; // dates..
7965 // combo boxes where name != hiddenName...
7966 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7967 ret[f.name] = f.getRawValue();
7969 ret[f.getName()] = v;
7976 * Clears all invalid messages in this form.
7977 * @return {BasicForm} this
7979 clearInvalid : function(){
7980 var items = this.getItems();
7982 items.each(function(f){
7993 * @return {BasicForm} this
7996 var items = this.getItems();
7997 items.each(function(f){
8001 Roo.each(this.childForms || [], function (f) {
8008 getItems : function()
8010 var r=new Roo.util.MixedCollection(false, function(o){
8011 return o.id || (o.id = Roo.id());
8013 var iter = function(el) {
8020 Roo.each(el.items,function(e) {
8037 Roo.apply(Roo.bootstrap.Form, {
8064 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8065 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8066 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8067 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8070 this.maskEl.top.enableDisplayMode("block");
8071 this.maskEl.left.enableDisplayMode("block");
8072 this.maskEl.bottom.enableDisplayMode("block");
8073 this.maskEl.right.enableDisplayMode("block");
8075 this.toolTip = new Roo.bootstrap.Tooltip({
8076 cls : 'roo-form-error-popover',
8078 'left' : ['r-l', [-2,0], 'right'],
8079 'right' : ['l-r', [2,0], 'left'],
8080 'bottom' : ['tl-bl', [0,2], 'top'],
8081 'top' : [ 'bl-tl', [0,-2], 'bottom']
8085 this.toolTip.render(Roo.get(document.body));
8087 this.toolTip.el.enableDisplayMode("block");
8089 Roo.get(document.body).on('click', function(){
8093 Roo.get(document.body).on('touchstart', function(){
8097 this.isApplied = true
8100 mask : function(form, target)
8104 this.target = target;
8106 if(!this.form.errorMask || !target.el){
8110 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8112 var ot = this.target.el.calcOffsetsTo(scrollable);
8114 var scrollTo = ot[1] - this.form.maskOffset;
8116 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8118 scrollable.scrollTo('top', scrollTo);
8120 var box = this.target.el.getBox();
8122 var zIndex = Roo.bootstrap.Modal.zIndex++;
8125 this.maskEl.top.setStyle('position', 'absolute');
8126 this.maskEl.top.setStyle('z-index', zIndex);
8127 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8128 this.maskEl.top.setLeft(0);
8129 this.maskEl.top.setTop(0);
8130 this.maskEl.top.show();
8132 this.maskEl.left.setStyle('position', 'absolute');
8133 this.maskEl.left.setStyle('z-index', zIndex);
8134 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8135 this.maskEl.left.setLeft(0);
8136 this.maskEl.left.setTop(box.y - this.padding);
8137 this.maskEl.left.show();
8139 this.maskEl.bottom.setStyle('position', 'absolute');
8140 this.maskEl.bottom.setStyle('z-index', zIndex);
8141 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8142 this.maskEl.bottom.setLeft(0);
8143 this.maskEl.bottom.setTop(box.bottom + this.padding);
8144 this.maskEl.bottom.show();
8146 this.maskEl.right.setStyle('position', 'absolute');
8147 this.maskEl.right.setStyle('z-index', zIndex);
8148 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8149 this.maskEl.right.setLeft(box.right + this.padding);
8150 this.maskEl.right.setTop(box.y - this.padding);
8151 this.maskEl.right.show();
8153 this.toolTip.bindEl = this.target.el;
8155 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8157 var tip = this.target.blankText;
8159 if(this.target.getValue() !== '' ) {
8160 if (this.target.errorText.length) {
8161 tip = this.target.errorText;
8162 } else if (this.target.regexText.length){
8163 tip = this.target.regexText;
8167 this.toolTip.show(tip);
8169 this.intervalID = window.setInterval(function() {
8170 Roo.bootstrap.Form.popover.unmask();
8173 window.onwheel = function(){ return false;};
8175 (function(){ this.isMasked = true; }).defer(500, this);
8181 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8185 this.maskEl.top.setStyle('position', 'absolute');
8186 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8187 this.maskEl.top.hide();
8189 this.maskEl.left.setStyle('position', 'absolute');
8190 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8191 this.maskEl.left.hide();
8193 this.maskEl.bottom.setStyle('position', 'absolute');
8194 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8195 this.maskEl.bottom.hide();
8197 this.maskEl.right.setStyle('position', 'absolute');
8198 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8199 this.maskEl.right.hide();
8201 this.toolTip.hide();
8203 this.toolTip.el.hide();
8205 window.onwheel = function(){ return true;};
8207 if(this.intervalID){
8208 window.clearInterval(this.intervalID);
8209 this.intervalID = false;
8212 this.isMasked = false;
8222 * Ext JS Library 1.1.1
8223 * Copyright(c) 2006-2007, Ext JS, LLC.
8225 * Originally Released Under LGPL - original licence link has changed is not relivant.
8228 * <script type="text/javascript">
8231 * @class Roo.form.VTypes
8232 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8235 Roo.form.VTypes = function(){
8236 // closure these in so they are only created once.
8237 var alpha = /^[a-zA-Z_]+$/;
8238 var alphanum = /^[a-zA-Z0-9_]+$/;
8239 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8240 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8242 // All these messages and functions are configurable
8245 * The function used to validate email addresses
8246 * @param {String} value The email address
8248 'email' : function(v){
8249 return email.test(v);
8252 * The error text to display when the email validation function returns false
8255 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8257 * The keystroke filter mask to be applied on email input
8260 'emailMask' : /[a-z0-9_\.\-@]/i,
8263 * The function used to validate URLs
8264 * @param {String} value The URL
8266 'url' : function(v){
8270 * The error text to display when the url validation function returns false
8273 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8276 * The function used to validate alpha values
8277 * @param {String} value The value
8279 'alpha' : function(v){
8280 return alpha.test(v);
8283 * The error text to display when the alpha validation function returns false
8286 'alphaText' : 'This field should only contain letters and _',
8288 * The keystroke filter mask to be applied on alpha input
8291 'alphaMask' : /[a-z_]/i,
8294 * The function used to validate alphanumeric values
8295 * @param {String} value The value
8297 'alphanum' : function(v){
8298 return alphanum.test(v);
8301 * The error text to display when the alphanumeric validation function returns false
8304 'alphanumText' : 'This field should only contain letters, numbers and _',
8306 * The keystroke filter mask to be applied on alphanumeric input
8309 'alphanumMask' : /[a-z0-9_]/i
8319 * @class Roo.bootstrap.Input
8320 * @extends Roo.bootstrap.Component
8321 * Bootstrap Input class
8322 * @cfg {Boolean} disabled is it disabled
8323 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8324 * @cfg {String} name name of the input
8325 * @cfg {string} fieldLabel - the label associated
8326 * @cfg {string} placeholder - placeholder to put in text.
8327 * @cfg {string} before - input group add on before
8328 * @cfg {string} after - input group add on after
8329 * @cfg {string} size - (lg|sm) or leave empty..
8330 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8331 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8332 * @cfg {Number} md colspan out of 12 for computer-sized screens
8333 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8334 * @cfg {string} value default value of the input
8335 * @cfg {Number} labelWidth set the width of label
8336 * @cfg {Number} labellg set the width of label (1-12)
8337 * @cfg {Number} labelmd set the width of label (1-12)
8338 * @cfg {Number} labelsm set the width of label (1-12)
8339 * @cfg {Number} labelxs set the width of label (1-12)
8340 * @cfg {String} labelAlign (top|left)
8341 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8342 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8343 * @cfg {String} indicatorpos (left|right) default left
8345 * @cfg {String} align (left|center|right) Default left
8346 * @cfg {Boolean} forceFeedback (true|false) Default false
8352 * Create a new Input
8353 * @param {Object} config The config object
8356 Roo.bootstrap.Input = function(config){
8358 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8363 * Fires when this field receives input focus.
8364 * @param {Roo.form.Field} this
8369 * Fires when this field loses input focus.
8370 * @param {Roo.form.Field} this
8375 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8376 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8377 * @param {Roo.form.Field} this
8378 * @param {Roo.EventObject} e The event object
8383 * Fires just before the field blurs if the field value has changed.
8384 * @param {Roo.form.Field} this
8385 * @param {Mixed} newValue The new value
8386 * @param {Mixed} oldValue The original value
8391 * Fires after the field has been marked as invalid.
8392 * @param {Roo.form.Field} this
8393 * @param {String} msg The validation message
8398 * Fires after the field has been validated with no errors.
8399 * @param {Roo.form.Field} this
8404 * Fires after the key up
8405 * @param {Roo.form.Field} this
8406 * @param {Roo.EventObject} e The event Object
8412 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8414 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8415 automatic validation (defaults to "keyup").
8417 validationEvent : "keyup",
8419 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8421 validateOnBlur : true,
8423 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8425 validationDelay : 250,
8427 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8429 focusClass : "x-form-focus", // not needed???
8433 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8435 invalidClass : "has-warning",
8438 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8440 validClass : "has-success",
8443 * @cfg {Boolean} hasFeedback (true|false) default true
8448 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8450 invalidFeedbackClass : "glyphicon-warning-sign",
8453 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8455 validFeedbackClass : "glyphicon-ok",
8458 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8460 selectOnFocus : false,
8463 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8467 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8472 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8474 disableKeyFilter : false,
8477 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8481 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8485 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8487 blankText : "Please complete this mandatory field",
8490 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8494 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8496 maxLength : Number.MAX_VALUE,
8498 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8500 minLengthText : "The minimum length for this field is {0}",
8502 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8504 maxLengthText : "The maximum length for this field is {0}",
8508 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8509 * If available, this function will be called only after the basic validators all return true, and will be passed the
8510 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8514 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8515 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8516 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8520 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8524 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8530 autocomplete: false,
8549 formatedValue : false,
8550 forceFeedback : false,
8552 indicatorpos : 'left',
8559 parentLabelAlign : function()
8562 while (parent.parent()) {
8563 parent = parent.parent();
8564 if (typeof(parent.labelAlign) !='undefined') {
8565 return parent.labelAlign;
8572 getAutoCreate : function()
8574 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8580 if(this.inputType != 'hidden'){
8581 cfg.cls = 'form-group' //input-group
8587 type : this.inputType,
8589 cls : 'form-control',
8590 placeholder : this.placeholder || '',
8591 autocomplete : this.autocomplete || 'new-password'
8595 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8598 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8599 input.maxLength = this.maxLength;
8602 if (this.disabled) {
8603 input.disabled=true;
8606 if (this.readOnly) {
8607 input.readonly=true;
8611 input.name = this.name;
8615 input.cls += ' input-' + this.size;
8619 ['xs','sm','md','lg'].map(function(size){
8620 if (settings[size]) {
8621 cfg.cls += ' col-' + size + '-' + settings[size];
8625 var inputblock = input;
8629 cls: 'glyphicon form-control-feedback'
8632 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8635 cls : 'has-feedback',
8643 if (this.before || this.after) {
8646 cls : 'input-group',
8650 if (this.before && typeof(this.before) == 'string') {
8652 inputblock.cn.push({
8654 cls : 'roo-input-before input-group-addon',
8658 if (this.before && typeof(this.before) == 'object') {
8659 this.before = Roo.factory(this.before);
8661 inputblock.cn.push({
8663 cls : 'roo-input-before input-group-' +
8664 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8668 inputblock.cn.push(input);
8670 if (this.after && typeof(this.after) == 'string') {
8671 inputblock.cn.push({
8673 cls : 'roo-input-after input-group-addon',
8677 if (this.after && typeof(this.after) == 'object') {
8678 this.after = Roo.factory(this.after);
8680 inputblock.cn.push({
8682 cls : 'roo-input-after input-group-' +
8683 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8687 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8688 inputblock.cls += ' has-feedback';
8689 inputblock.cn.push(feedback);
8693 if (align ==='left' && this.fieldLabel.length) {
8695 cfg.cls += ' roo-form-group-label-left';
8700 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8701 tooltip : 'This field is required'
8706 cls : 'control-label',
8707 html : this.fieldLabel
8718 var labelCfg = cfg.cn[1];
8719 var contentCfg = cfg.cn[2];
8721 if(this.indicatorpos == 'right'){
8726 cls : 'control-label',
8727 html : this.fieldLabel
8732 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8733 tooltip : 'This field is required'
8744 labelCfg = cfg.cn[0];
8745 contentCfg = cfg.cn[2];
8749 if(this.labelWidth > 12){
8750 labelCfg.style = "width: " + this.labelWidth + 'px';
8753 if(this.labelWidth < 13 && this.labelmd == 0){
8754 this.labelmd = this.labelWidth;
8757 if(this.labellg > 0){
8758 labelCfg.cls += ' col-lg-' + this.labellg;
8759 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8762 if(this.labelmd > 0){
8763 labelCfg.cls += ' col-md-' + this.labelmd;
8764 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8767 if(this.labelsm > 0){
8768 labelCfg.cls += ' col-sm-' + this.labelsm;
8769 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8772 if(this.labelxs > 0){
8773 labelCfg.cls += ' col-xs-' + this.labelxs;
8774 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8778 } else if ( this.fieldLabel.length) {
8783 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8784 tooltip : 'This field is required'
8788 //cls : 'input-group-addon',
8789 html : this.fieldLabel
8797 if(this.indicatorpos == 'right'){
8802 //cls : 'input-group-addon',
8803 html : this.fieldLabel
8808 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8809 tooltip : 'This field is required'
8829 if (this.parentType === 'Navbar' && this.parent().bar) {
8830 cfg.cls += ' navbar-form';
8833 if (this.parentType === 'NavGroup') {
8834 cfg.cls += ' navbar-form';
8842 * return the real input element.
8844 inputEl: function ()
8846 return this.el.select('input.form-control',true).first();
8849 tooltipEl : function()
8851 return this.inputEl();
8854 indicatorEl : function()
8856 var indicator = this.el.select('i.roo-required-indicator',true).first();
8866 setDisabled : function(v)
8868 var i = this.inputEl().dom;
8870 i.removeAttribute('disabled');
8874 i.setAttribute('disabled','true');
8876 initEvents : function()
8879 this.inputEl().on("keydown" , this.fireKey, this);
8880 this.inputEl().on("focus", this.onFocus, this);
8881 this.inputEl().on("blur", this.onBlur, this);
8883 this.inputEl().relayEvent('keyup', this);
8885 this.indicator = this.indicatorEl();
8888 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8889 this.indicator.hide();
8892 // reference to original value for reset
8893 this.originalValue = this.getValue();
8894 //Roo.form.TextField.superclass.initEvents.call(this);
8895 if(this.validationEvent == 'keyup'){
8896 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8897 this.inputEl().on('keyup', this.filterValidation, this);
8899 else if(this.validationEvent !== false){
8900 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8903 if(this.selectOnFocus){
8904 this.on("focus", this.preFocus, this);
8907 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8908 this.inputEl().on("keypress", this.filterKeys, this);
8910 this.inputEl().relayEvent('keypress', this);
8913 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8914 this.el.on("click", this.autoSize, this);
8917 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8918 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8921 if (typeof(this.before) == 'object') {
8922 this.before.render(this.el.select('.roo-input-before',true).first());
8924 if (typeof(this.after) == 'object') {
8925 this.after.render(this.el.select('.roo-input-after',true).first());
8930 filterValidation : function(e){
8931 if(!e.isNavKeyPress()){
8932 this.validationTask.delay(this.validationDelay);
8936 * Validates the field value
8937 * @return {Boolean} True if the value is valid, else false
8939 validate : function(){
8940 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8941 if(this.disabled || this.validateValue(this.getRawValue())){
8952 * Validates a value according to the field's validation rules and marks the field as invalid
8953 * if the validation fails
8954 * @param {Mixed} value The value to validate
8955 * @return {Boolean} True if the value is valid, else false
8957 validateValue : function(value){
8958 if(value.length < 1) { // if it's blank
8959 if(this.allowBlank){
8962 return this.inputEl().hasClass('hide') ? true : false;
8965 if(value.length < this.minLength){
8968 if(value.length > this.maxLength){
8972 var vt = Roo.form.VTypes;
8973 if(!vt[this.vtype](value, this)){
8977 if(typeof this.validator == "function"){
8978 var msg = this.validator(value);
8984 if(this.regex && !this.regex.test(value)){
8994 fireKey : function(e){
8995 //Roo.log('field ' + e.getKey());
8996 if(e.isNavKeyPress()){
8997 this.fireEvent("specialkey", this, e);
9000 focus : function (selectText){
9002 this.inputEl().focus();
9003 if(selectText === true){
9004 this.inputEl().dom.select();
9010 onFocus : function(){
9011 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9012 // this.el.addClass(this.focusClass);
9015 this.hasFocus = true;
9016 this.startValue = this.getValue();
9017 this.fireEvent("focus", this);
9021 beforeBlur : Roo.emptyFn,
9025 onBlur : function(){
9027 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9028 //this.el.removeClass(this.focusClass);
9030 this.hasFocus = false;
9031 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9034 var v = this.getValue();
9035 if(String(v) !== String(this.startValue)){
9036 this.fireEvent('change', this, v, this.startValue);
9038 this.fireEvent("blur", this);
9042 * Resets the current field value to the originally loaded value and clears any validation messages
9045 this.setValue(this.originalValue);
9049 * Returns the name of the field
9050 * @return {Mixed} name The name field
9052 getName: function(){
9056 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9057 * @return {Mixed} value The field value
9059 getValue : function(){
9061 var v = this.inputEl().getValue();
9066 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9067 * @return {Mixed} value The field value
9069 getRawValue : function(){
9070 var v = this.inputEl().getValue();
9076 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9077 * @param {Mixed} value The value to set
9079 setRawValue : function(v){
9080 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9083 selectText : function(start, end){
9084 var v = this.getRawValue();
9086 start = start === undefined ? 0 : start;
9087 end = end === undefined ? v.length : end;
9088 var d = this.inputEl().dom;
9089 if(d.setSelectionRange){
9090 d.setSelectionRange(start, end);
9091 }else if(d.createTextRange){
9092 var range = d.createTextRange();
9093 range.moveStart("character", start);
9094 range.moveEnd("character", v.length-end);
9101 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9102 * @param {Mixed} value The value to set
9104 setValue : function(v){
9107 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9113 processValue : function(value){
9114 if(this.stripCharsRe){
9115 var newValue = value.replace(this.stripCharsRe, '');
9116 if(newValue !== value){
9117 this.setRawValue(newValue);
9124 preFocus : function(){
9126 if(this.selectOnFocus){
9127 this.inputEl().dom.select();
9130 filterKeys : function(e){
9132 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9135 var c = e.getCharCode(), cc = String.fromCharCode(c);
9136 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9139 if(!this.maskRe.test(cc)){
9144 * Clear any invalid styles/messages for this field
9146 clearInvalid : function(){
9148 if(!this.el || this.preventMark){ // not rendered
9153 this.el.removeClass(this.invalidClass);
9155 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9157 var feedback = this.el.select('.form-control-feedback', true).first();
9160 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9165 this.fireEvent('valid', this);
9169 * Mark this field as valid
9171 markValid : function()
9173 if(!this.el || this.preventMark){ // not rendered...
9177 this.el.removeClass([this.invalidClass, this.validClass]);
9179 var feedback = this.el.select('.form-control-feedback', true).first();
9182 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9189 if(this.allowBlank && !this.getRawValue().length){
9194 this.indicator.hide();
9197 this.el.addClass(this.validClass);
9199 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9201 var feedback = this.el.select('.form-control-feedback', true).first();
9204 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9205 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9210 this.fireEvent('valid', this);
9214 * Mark this field as invalid
9215 * @param {String} msg The validation message
9217 markInvalid : function(msg)
9219 if(!this.el || this.preventMark){ // not rendered
9223 this.el.removeClass([this.invalidClass, this.validClass]);
9225 var feedback = this.el.select('.form-control-feedback', true).first();
9228 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9235 if(this.allowBlank && !this.getRawValue().length){
9240 this.indicator.show();
9243 this.el.addClass(this.invalidClass);
9245 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9247 var feedback = this.el.select('.form-control-feedback', true).first();
9250 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9252 if(this.getValue().length || this.forceFeedback){
9253 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9260 this.fireEvent('invalid', this, msg);
9263 SafariOnKeyDown : function(event)
9265 // this is a workaround for a password hang bug on chrome/ webkit.
9266 if (this.inputEl().dom.type != 'password') {
9270 var isSelectAll = false;
9272 if(this.inputEl().dom.selectionEnd > 0){
9273 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9275 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9276 event.preventDefault();
9281 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9283 event.preventDefault();
9284 // this is very hacky as keydown always get's upper case.
9286 var cc = String.fromCharCode(event.getCharCode());
9287 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9291 adjustWidth : function(tag, w){
9292 tag = tag.toLowerCase();
9293 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9294 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9298 if(tag == 'textarea'){
9301 }else if(Roo.isOpera){
9305 if(tag == 'textarea'){
9324 * @class Roo.bootstrap.TextArea
9325 * @extends Roo.bootstrap.Input
9326 * Bootstrap TextArea class
9327 * @cfg {Number} cols Specifies the visible width of a text area
9328 * @cfg {Number} rows Specifies the visible number of lines in a text area
9329 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9330 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9331 * @cfg {string} html text
9334 * Create a new TextArea
9335 * @param {Object} config The config object
9338 Roo.bootstrap.TextArea = function(config){
9339 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9343 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9353 getAutoCreate : function(){
9355 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9366 value : this.value || '',
9367 html: this.html || '',
9368 cls : 'form-control',
9369 placeholder : this.placeholder || ''
9373 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9374 input.maxLength = this.maxLength;
9378 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9382 input.cols = this.cols;
9385 if (this.readOnly) {
9386 input.readonly = true;
9390 input.name = this.name;
9394 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9398 ['xs','sm','md','lg'].map(function(size){
9399 if (settings[size]) {
9400 cfg.cls += ' col-' + size + '-' + settings[size];
9404 var inputblock = input;
9406 if(this.hasFeedback && !this.allowBlank){
9410 cls: 'glyphicon form-control-feedback'
9414 cls : 'has-feedback',
9423 if (this.before || this.after) {
9426 cls : 'input-group',
9430 inputblock.cn.push({
9432 cls : 'input-group-addon',
9437 inputblock.cn.push(input);
9439 if(this.hasFeedback && !this.allowBlank){
9440 inputblock.cls += ' has-feedback';
9441 inputblock.cn.push(feedback);
9445 inputblock.cn.push({
9447 cls : 'input-group-addon',
9454 if (align ==='left' && this.fieldLabel.length) {
9459 cls : 'control-label',
9460 html : this.fieldLabel
9471 if(this.labelWidth > 12){
9472 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9475 if(this.labelWidth < 13 && this.labelmd == 0){
9476 this.labelmd = this.labelWidth;
9479 if(this.labellg > 0){
9480 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9481 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9484 if(this.labelmd > 0){
9485 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9486 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9489 if(this.labelsm > 0){
9490 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9491 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9494 if(this.labelxs > 0){
9495 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9496 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9499 } else if ( this.fieldLabel.length) {
9504 //cls : 'input-group-addon',
9505 html : this.fieldLabel
9523 if (this.disabled) {
9524 input.disabled=true;
9531 * return the real textarea element.
9533 inputEl: function ()
9535 return this.el.select('textarea.form-control',true).first();
9539 * Clear any invalid styles/messages for this field
9541 clearInvalid : function()
9544 if(!this.el || this.preventMark){ // not rendered
9548 var label = this.el.select('label', true).first();
9549 var icon = this.el.select('i.fa-star', true).first();
9555 this.el.removeClass(this.invalidClass);
9557 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9559 var feedback = this.el.select('.form-control-feedback', true).first();
9562 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9567 this.fireEvent('valid', this);
9571 * Mark this field as valid
9573 markValid : function()
9575 if(!this.el || this.preventMark){ // not rendered
9579 this.el.removeClass([this.invalidClass, this.validClass]);
9581 var feedback = this.el.select('.form-control-feedback', true).first();
9584 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9587 if(this.disabled || this.allowBlank){
9591 var label = this.el.select('label', true).first();
9592 var icon = this.el.select('i.fa-star', true).first();
9598 this.el.addClass(this.validClass);
9600 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9602 var feedback = this.el.select('.form-control-feedback', true).first();
9605 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9606 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9611 this.fireEvent('valid', this);
9615 * Mark this field as invalid
9616 * @param {String} msg The validation message
9618 markInvalid : function(msg)
9620 if(!this.el || this.preventMark){ // not rendered
9624 this.el.removeClass([this.invalidClass, this.validClass]);
9626 var feedback = this.el.select('.form-control-feedback', true).first();
9629 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9632 if(this.disabled || this.allowBlank){
9636 var label = this.el.select('label', true).first();
9637 var icon = this.el.select('i.fa-star', true).first();
9639 if(!this.getValue().length && label && !icon){
9640 this.el.createChild({
9642 cls : 'text-danger fa fa-lg fa-star',
9643 tooltip : 'This field is required',
9644 style : 'margin-right:5px;'
9648 this.el.addClass(this.invalidClass);
9650 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9652 var feedback = this.el.select('.form-control-feedback', true).first();
9655 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9657 if(this.getValue().length || this.forceFeedback){
9658 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9665 this.fireEvent('invalid', this, msg);
9673 * trigger field - base class for combo..
9678 * @class Roo.bootstrap.TriggerField
9679 * @extends Roo.bootstrap.Input
9680 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9681 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9682 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9683 * for which you can provide a custom implementation. For example:
9685 var trigger = new Roo.bootstrap.TriggerField();
9686 trigger.onTriggerClick = myTriggerFn;
9687 trigger.applyTo('my-field');
9690 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9691 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9692 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9693 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9694 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9697 * Create a new TriggerField.
9698 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9699 * to the base TextField)
9701 Roo.bootstrap.TriggerField = function(config){
9702 this.mimicing = false;
9703 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9706 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9708 * @cfg {String} triggerClass A CSS class to apply to the trigger
9711 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9716 * @cfg {Boolean} removable (true|false) special filter default false
9720 /** @cfg {Boolean} grow @hide */
9721 /** @cfg {Number} growMin @hide */
9722 /** @cfg {Number} growMax @hide */
9728 autoSize: Roo.emptyFn,
9735 actionMode : 'wrap',
9740 getAutoCreate : function(){
9742 var align = this.labelAlign || this.parentLabelAlign();
9747 cls: 'form-group' //input-group
9754 type : this.inputType,
9755 cls : 'form-control',
9756 autocomplete: 'new-password',
9757 placeholder : this.placeholder || ''
9761 input.name = this.name;
9764 input.cls += ' input-' + this.size;
9767 if (this.disabled) {
9768 input.disabled=true;
9771 var inputblock = input;
9773 if(this.hasFeedback && !this.allowBlank){
9777 cls: 'glyphicon form-control-feedback'
9780 if(this.removable && !this.editable && !this.tickable){
9782 cls : 'has-feedback',
9788 cls : 'roo-combo-removable-btn close'
9795 cls : 'has-feedback',
9804 if(this.removable && !this.editable && !this.tickable){
9806 cls : 'roo-removable',
9812 cls : 'roo-combo-removable-btn close'
9819 if (this.before || this.after) {
9822 cls : 'input-group',
9826 inputblock.cn.push({
9828 cls : 'input-group-addon',
9833 inputblock.cn.push(input);
9835 if(this.hasFeedback && !this.allowBlank){
9836 inputblock.cls += ' has-feedback';
9837 inputblock.cn.push(feedback);
9841 inputblock.cn.push({
9843 cls : 'input-group-addon',
9856 cls: 'form-hidden-field'
9870 cls: 'form-hidden-field'
9874 cls: 'roo-select2-choices',
9878 cls: 'roo-select2-search-field',
9891 cls: 'roo-select2-container input-group',
9896 // cls: 'typeahead typeahead-long dropdown-menu',
9897 // style: 'display:none'
9902 if(!this.multiple && this.showToggleBtn){
9908 if (this.caret != false) {
9911 cls: 'fa fa-' + this.caret
9918 cls : 'input-group-addon btn dropdown-toggle',
9923 cls: 'combobox-clear',
9937 combobox.cls += ' roo-select2-container-multi';
9940 if (align ==='left' && this.fieldLabel.length) {
9942 cfg.cls += ' roo-form-group-label-left';
9947 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9948 tooltip : 'This field is required'
9953 cls : 'control-label',
9954 html : this.fieldLabel
9966 var labelCfg = cfg.cn[1];
9967 var contentCfg = cfg.cn[2];
9969 if(this.indicatorpos == 'right'){
9974 cls : 'control-label',
9978 html : this.fieldLabel
9982 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9983 tooltip : 'This field is required'
9996 labelCfg = cfg.cn[0];
9997 contentCfg = cfg.cn[1];
10000 if(this.labelWidth > 12){
10001 labelCfg.style = "width: " + this.labelWidth + 'px';
10004 if(this.labelWidth < 13 && this.labelmd == 0){
10005 this.labelmd = this.labelWidth;
10008 if(this.labellg > 0){
10009 labelCfg.cls += ' col-lg-' + this.labellg;
10010 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10013 if(this.labelmd > 0){
10014 labelCfg.cls += ' col-md-' + this.labelmd;
10015 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10018 if(this.labelsm > 0){
10019 labelCfg.cls += ' col-sm-' + this.labelsm;
10020 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10023 if(this.labelxs > 0){
10024 labelCfg.cls += ' col-xs-' + this.labelxs;
10025 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10028 } else if ( this.fieldLabel.length) {
10029 // Roo.log(" label");
10033 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10034 tooltip : 'This field is required'
10038 //cls : 'input-group-addon',
10039 html : this.fieldLabel
10047 if(this.indicatorpos == 'right'){
10055 html : this.fieldLabel
10059 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10060 tooltip : 'This field is required'
10073 // Roo.log(" no label && no align");
10080 ['xs','sm','md','lg'].map(function(size){
10081 if (settings[size]) {
10082 cfg.cls += ' col-' + size + '-' + settings[size];
10093 onResize : function(w, h){
10094 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10095 // if(typeof w == 'number'){
10096 // var x = w - this.trigger.getWidth();
10097 // this.inputEl().setWidth(this.adjustWidth('input', x));
10098 // this.trigger.setStyle('left', x+'px');
10103 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10106 getResizeEl : function(){
10107 return this.inputEl();
10111 getPositionEl : function(){
10112 return this.inputEl();
10116 alignErrorIcon : function(){
10117 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10121 initEvents : function(){
10125 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10126 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10127 if(!this.multiple && this.showToggleBtn){
10128 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10129 if(this.hideTrigger){
10130 this.trigger.setDisplayed(false);
10132 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10136 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10139 if(this.removable && !this.editable && !this.tickable){
10140 var close = this.closeTriggerEl();
10143 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10144 close.on('click', this.removeBtnClick, this, close);
10148 //this.trigger.addClassOnOver('x-form-trigger-over');
10149 //this.trigger.addClassOnClick('x-form-trigger-click');
10152 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10156 closeTriggerEl : function()
10158 var close = this.el.select('.roo-combo-removable-btn', true).first();
10159 return close ? close : false;
10162 removeBtnClick : function(e, h, el)
10164 e.preventDefault();
10166 if(this.fireEvent("remove", this) !== false){
10168 this.fireEvent("afterremove", this)
10172 createList : function()
10174 this.list = Roo.get(document.body).createChild({
10176 cls: 'typeahead typeahead-long dropdown-menu',
10177 style: 'display:none'
10180 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10185 initTrigger : function(){
10190 onDestroy : function(){
10192 this.trigger.removeAllListeners();
10193 // this.trigger.remove();
10196 // this.wrap.remove();
10198 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10202 onFocus : function(){
10203 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10205 if(!this.mimicing){
10206 this.wrap.addClass('x-trigger-wrap-focus');
10207 this.mimicing = true;
10208 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10209 if(this.monitorTab){
10210 this.el.on("keydown", this.checkTab, this);
10217 checkTab : function(e){
10218 if(e.getKey() == e.TAB){
10219 this.triggerBlur();
10224 onBlur : function(){
10229 mimicBlur : function(e, t){
10231 if(!this.wrap.contains(t) && this.validateBlur()){
10232 this.triggerBlur();
10238 triggerBlur : function(){
10239 this.mimicing = false;
10240 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10241 if(this.monitorTab){
10242 this.el.un("keydown", this.checkTab, this);
10244 //this.wrap.removeClass('x-trigger-wrap-focus');
10245 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10249 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10250 validateBlur : function(e, t){
10255 onDisable : function(){
10256 this.inputEl().dom.disabled = true;
10257 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10259 // this.wrap.addClass('x-item-disabled');
10264 onEnable : function(){
10265 this.inputEl().dom.disabled = false;
10266 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10268 // this.el.removeClass('x-item-disabled');
10273 onShow : function(){
10274 var ae = this.getActionEl();
10277 ae.dom.style.display = '';
10278 ae.dom.style.visibility = 'visible';
10284 onHide : function(){
10285 var ae = this.getActionEl();
10286 ae.dom.style.display = 'none';
10290 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10291 * by an implementing function.
10293 * @param {EventObject} e
10295 onTriggerClick : Roo.emptyFn
10299 * Ext JS Library 1.1.1
10300 * Copyright(c) 2006-2007, Ext JS, LLC.
10302 * Originally Released Under LGPL - original licence link has changed is not relivant.
10305 * <script type="text/javascript">
10310 * @class Roo.data.SortTypes
10312 * Defines the default sorting (casting?) comparison functions used when sorting data.
10314 Roo.data.SortTypes = {
10316 * Default sort that does nothing
10317 * @param {Mixed} s The value being converted
10318 * @return {Mixed} The comparison value
10320 none : function(s){
10325 * The regular expression used to strip tags
10329 stripTagsRE : /<\/?[^>]+>/gi,
10332 * Strips all HTML tags to sort on text only
10333 * @param {Mixed} s The value being converted
10334 * @return {String} The comparison value
10336 asText : function(s){
10337 return String(s).replace(this.stripTagsRE, "");
10341 * Strips all HTML tags to sort on text only - Case insensitive
10342 * @param {Mixed} s The value being converted
10343 * @return {String} The comparison value
10345 asUCText : function(s){
10346 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10350 * Case insensitive string
10351 * @param {Mixed} s The value being converted
10352 * @return {String} The comparison value
10354 asUCString : function(s) {
10355 return String(s).toUpperCase();
10360 * @param {Mixed} s The value being converted
10361 * @return {Number} The comparison value
10363 asDate : function(s) {
10367 if(s instanceof Date){
10368 return s.getTime();
10370 return Date.parse(String(s));
10375 * @param {Mixed} s The value being converted
10376 * @return {Float} The comparison value
10378 asFloat : function(s) {
10379 var val = parseFloat(String(s).replace(/,/g, ""));
10388 * @param {Mixed} s The value being converted
10389 * @return {Number} The comparison value
10391 asInt : function(s) {
10392 var val = parseInt(String(s).replace(/,/g, ""));
10400 * Ext JS Library 1.1.1
10401 * Copyright(c) 2006-2007, Ext JS, LLC.
10403 * Originally Released Under LGPL - original licence link has changed is not relivant.
10406 * <script type="text/javascript">
10410 * @class Roo.data.Record
10411 * Instances of this class encapsulate both record <em>definition</em> information, and record
10412 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10413 * to access Records cached in an {@link Roo.data.Store} object.<br>
10415 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10416 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10419 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10421 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10422 * {@link #create}. The parameters are the same.
10423 * @param {Array} data An associative Array of data values keyed by the field name.
10424 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10425 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10426 * not specified an integer id is generated.
10428 Roo.data.Record = function(data, id){
10429 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10434 * Generate a constructor for a specific record layout.
10435 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10436 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10437 * Each field definition object may contain the following properties: <ul>
10438 * <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,
10439 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10440 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10441 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10442 * is being used, then this is a string containing the javascript expression to reference the data relative to
10443 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10444 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10445 * this may be omitted.</p></li>
10446 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10447 * <ul><li>auto (Default, implies no conversion)</li>
10452 * <li>date</li></ul></p></li>
10453 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10454 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10455 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10456 * by the Reader into an object that will be stored in the Record. It is passed the
10457 * following parameters:<ul>
10458 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10460 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10462 * <br>usage:<br><pre><code>
10463 var TopicRecord = Roo.data.Record.create(
10464 {name: 'title', mapping: 'topic_title'},
10465 {name: 'author', mapping: 'username'},
10466 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10467 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10468 {name: 'lastPoster', mapping: 'user2'},
10469 {name: 'excerpt', mapping: 'post_text'}
10472 var myNewRecord = new TopicRecord({
10473 title: 'Do my job please',
10476 lastPost: new Date(),
10477 lastPoster: 'Animal',
10478 excerpt: 'No way dude!'
10480 myStore.add(myNewRecord);
10485 Roo.data.Record.create = function(o){
10486 var f = function(){
10487 f.superclass.constructor.apply(this, arguments);
10489 Roo.extend(f, Roo.data.Record);
10490 var p = f.prototype;
10491 p.fields = new Roo.util.MixedCollection(false, function(field){
10494 for(var i = 0, len = o.length; i < len; i++){
10495 p.fields.add(new Roo.data.Field(o[i]));
10497 f.getField = function(name){
10498 return p.fields.get(name);
10503 Roo.data.Record.AUTO_ID = 1000;
10504 Roo.data.Record.EDIT = 'edit';
10505 Roo.data.Record.REJECT = 'reject';
10506 Roo.data.Record.COMMIT = 'commit';
10508 Roo.data.Record.prototype = {
10510 * Readonly flag - true if this record has been modified.
10519 join : function(store){
10520 this.store = store;
10524 * Set the named field to the specified value.
10525 * @param {String} name The name of the field to set.
10526 * @param {Object} value The value to set the field to.
10528 set : function(name, value){
10529 if(this.data[name] == value){
10533 if(!this.modified){
10534 this.modified = {};
10536 if(typeof this.modified[name] == 'undefined'){
10537 this.modified[name] = this.data[name];
10539 this.data[name] = value;
10540 if(!this.editing && this.store){
10541 this.store.afterEdit(this);
10546 * Get the value of the named field.
10547 * @param {String} name The name of the field to get the value of.
10548 * @return {Object} The value of the field.
10550 get : function(name){
10551 return this.data[name];
10555 beginEdit : function(){
10556 this.editing = true;
10557 this.modified = {};
10561 cancelEdit : function(){
10562 this.editing = false;
10563 delete this.modified;
10567 endEdit : function(){
10568 this.editing = false;
10569 if(this.dirty && this.store){
10570 this.store.afterEdit(this);
10575 * Usually called by the {@link Roo.data.Store} which owns the Record.
10576 * Rejects all changes made to the Record since either creation, or the last commit operation.
10577 * Modified fields are reverted to their original values.
10579 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10580 * of reject operations.
10582 reject : function(){
10583 var m = this.modified;
10585 if(typeof m[n] != "function"){
10586 this.data[n] = m[n];
10589 this.dirty = false;
10590 delete this.modified;
10591 this.editing = false;
10593 this.store.afterReject(this);
10598 * Usually called by the {@link Roo.data.Store} which owns the Record.
10599 * Commits all changes made to the Record since either creation, or the last commit operation.
10601 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10602 * of commit operations.
10604 commit : function(){
10605 this.dirty = false;
10606 delete this.modified;
10607 this.editing = false;
10609 this.store.afterCommit(this);
10614 hasError : function(){
10615 return this.error != null;
10619 clearError : function(){
10624 * Creates a copy of this record.
10625 * @param {String} id (optional) A new record id if you don't want to use this record's id
10628 copy : function(newId) {
10629 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10633 * Ext JS Library 1.1.1
10634 * Copyright(c) 2006-2007, Ext JS, LLC.
10636 * Originally Released Under LGPL - original licence link has changed is not relivant.
10639 * <script type="text/javascript">
10645 * @class Roo.data.Store
10646 * @extends Roo.util.Observable
10647 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10648 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10650 * 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
10651 * has no knowledge of the format of the data returned by the Proxy.<br>
10653 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10654 * instances from the data object. These records are cached and made available through accessor functions.
10656 * Creates a new Store.
10657 * @param {Object} config A config object containing the objects needed for the Store to access data,
10658 * and read the data into Records.
10660 Roo.data.Store = function(config){
10661 this.data = new Roo.util.MixedCollection(false);
10662 this.data.getKey = function(o){
10665 this.baseParams = {};
10667 this.paramNames = {
10672 "multisort" : "_multisort"
10675 if(config && config.data){
10676 this.inlineData = config.data;
10677 delete config.data;
10680 Roo.apply(this, config);
10682 if(this.reader){ // reader passed
10683 this.reader = Roo.factory(this.reader, Roo.data);
10684 this.reader.xmodule = this.xmodule || false;
10685 if(!this.recordType){
10686 this.recordType = this.reader.recordType;
10688 if(this.reader.onMetaChange){
10689 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10693 if(this.recordType){
10694 this.fields = this.recordType.prototype.fields;
10696 this.modified = [];
10700 * @event datachanged
10701 * Fires when the data cache has changed, and a widget which is using this Store
10702 * as a Record cache should refresh its view.
10703 * @param {Store} this
10705 datachanged : true,
10707 * @event metachange
10708 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10709 * @param {Store} this
10710 * @param {Object} meta The JSON metadata
10715 * Fires when Records have been added to the Store
10716 * @param {Store} this
10717 * @param {Roo.data.Record[]} records The array of Records added
10718 * @param {Number} index The index at which the record(s) were added
10723 * Fires when a Record has been removed from the Store
10724 * @param {Store} this
10725 * @param {Roo.data.Record} record The Record that was removed
10726 * @param {Number} index The index at which the record was removed
10731 * Fires when a Record has been updated
10732 * @param {Store} this
10733 * @param {Roo.data.Record} record The Record that was updated
10734 * @param {String} operation The update operation being performed. Value may be one of:
10736 Roo.data.Record.EDIT
10737 Roo.data.Record.REJECT
10738 Roo.data.Record.COMMIT
10744 * Fires when the data cache has been cleared.
10745 * @param {Store} this
10749 * @event beforeload
10750 * Fires before a request is made for a new data object. If the beforeload handler returns false
10751 * the load action will be canceled.
10752 * @param {Store} this
10753 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10757 * @event beforeloadadd
10758 * Fires after a new set of Records has been loaded.
10759 * @param {Store} this
10760 * @param {Roo.data.Record[]} records The Records that were loaded
10761 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10763 beforeloadadd : true,
10766 * Fires after a new set of Records has been loaded, before they are added to the store.
10767 * @param {Store} this
10768 * @param {Roo.data.Record[]} records The Records that were loaded
10769 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10770 * @params {Object} return from reader
10774 * @event loadexception
10775 * Fires if an exception occurs in the Proxy during loading.
10776 * Called with the signature of the Proxy's "loadexception" event.
10777 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10780 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10781 * @param {Object} load options
10782 * @param {Object} jsonData from your request (normally this contains the Exception)
10784 loadexception : true
10788 this.proxy = Roo.factory(this.proxy, Roo.data);
10789 this.proxy.xmodule = this.xmodule || false;
10790 this.relayEvents(this.proxy, ["loadexception"]);
10792 this.sortToggle = {};
10793 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10795 Roo.data.Store.superclass.constructor.call(this);
10797 if(this.inlineData){
10798 this.loadData(this.inlineData);
10799 delete this.inlineData;
10803 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10805 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10806 * without a remote query - used by combo/forms at present.
10810 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10813 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10816 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10817 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10820 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10821 * on any HTTP request
10824 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10827 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10831 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10832 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10834 remoteSort : false,
10837 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10838 * loaded or when a record is removed. (defaults to false).
10840 pruneModifiedRecords : false,
10843 lastOptions : null,
10846 * Add Records to the Store and fires the add event.
10847 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10849 add : function(records){
10850 records = [].concat(records);
10851 for(var i = 0, len = records.length; i < len; i++){
10852 records[i].join(this);
10854 var index = this.data.length;
10855 this.data.addAll(records);
10856 this.fireEvent("add", this, records, index);
10860 * Remove a Record from the Store and fires the remove event.
10861 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10863 remove : function(record){
10864 var index = this.data.indexOf(record);
10865 this.data.removeAt(index);
10866 if(this.pruneModifiedRecords){
10867 this.modified.remove(record);
10869 this.fireEvent("remove", this, record, index);
10873 * Remove all Records from the Store and fires the clear event.
10875 removeAll : function(){
10877 if(this.pruneModifiedRecords){
10878 this.modified = [];
10880 this.fireEvent("clear", this);
10884 * Inserts Records to the Store at the given index and fires the add event.
10885 * @param {Number} index The start index at which to insert the passed Records.
10886 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10888 insert : function(index, records){
10889 records = [].concat(records);
10890 for(var i = 0, len = records.length; i < len; i++){
10891 this.data.insert(index, records[i]);
10892 records[i].join(this);
10894 this.fireEvent("add", this, records, index);
10898 * Get the index within the cache of the passed Record.
10899 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10900 * @return {Number} The index of the passed Record. Returns -1 if not found.
10902 indexOf : function(record){
10903 return this.data.indexOf(record);
10907 * Get the index within the cache of the Record with the passed id.
10908 * @param {String} id The id of the Record to find.
10909 * @return {Number} The index of the Record. Returns -1 if not found.
10911 indexOfId : function(id){
10912 return this.data.indexOfKey(id);
10916 * Get the Record with the specified id.
10917 * @param {String} id The id of the Record to find.
10918 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10920 getById : function(id){
10921 return this.data.key(id);
10925 * Get the Record at the specified index.
10926 * @param {Number} index The index of the Record to find.
10927 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10929 getAt : function(index){
10930 return this.data.itemAt(index);
10934 * Returns a range of Records between specified indices.
10935 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10936 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10937 * @return {Roo.data.Record[]} An array of Records
10939 getRange : function(start, end){
10940 return this.data.getRange(start, end);
10944 storeOptions : function(o){
10945 o = Roo.apply({}, o);
10948 this.lastOptions = o;
10952 * Loads the Record cache from the configured Proxy using the configured Reader.
10954 * If using remote paging, then the first load call must specify the <em>start</em>
10955 * and <em>limit</em> properties in the options.params property to establish the initial
10956 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10958 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10959 * and this call will return before the new data has been loaded. Perform any post-processing
10960 * in a callback function, or in a "load" event handler.</strong>
10962 * @param {Object} options An object containing properties which control loading options:<ul>
10963 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10964 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10965 * passed the following arguments:<ul>
10966 * <li>r : Roo.data.Record[]</li>
10967 * <li>options: Options object from the load call</li>
10968 * <li>success: Boolean success indicator</li></ul></li>
10969 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10970 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10973 load : function(options){
10974 options = options || {};
10975 if(this.fireEvent("beforeload", this, options) !== false){
10976 this.storeOptions(options);
10977 var p = Roo.apply(options.params || {}, this.baseParams);
10978 // if meta was not loaded from remote source.. try requesting it.
10979 if (!this.reader.metaFromRemote) {
10980 p._requestMeta = 1;
10982 if(this.sortInfo && this.remoteSort){
10983 var pn = this.paramNames;
10984 p[pn["sort"]] = this.sortInfo.field;
10985 p[pn["dir"]] = this.sortInfo.direction;
10987 if (this.multiSort) {
10988 var pn = this.paramNames;
10989 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10992 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10997 * Reloads the Record cache from the configured Proxy using the configured Reader and
10998 * the options from the last load operation performed.
10999 * @param {Object} options (optional) An object containing properties which may override the options
11000 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11001 * the most recently used options are reused).
11003 reload : function(options){
11004 this.load(Roo.applyIf(options||{}, this.lastOptions));
11008 // Called as a callback by the Reader during a load operation.
11009 loadRecords : function(o, options, success){
11010 if(!o || success === false){
11011 if(success !== false){
11012 this.fireEvent("load", this, [], options, o);
11014 if(options.callback){
11015 options.callback.call(options.scope || this, [], options, false);
11019 // if data returned failure - throw an exception.
11020 if (o.success === false) {
11021 // show a message if no listener is registered.
11022 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11023 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11025 // loadmask wil be hooked into this..
11026 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11029 var r = o.records, t = o.totalRecords || r.length;
11031 this.fireEvent("beforeloadadd", this, r, options, o);
11033 if(!options || options.add !== true){
11034 if(this.pruneModifiedRecords){
11035 this.modified = [];
11037 for(var i = 0, len = r.length; i < len; i++){
11041 this.data = this.snapshot;
11042 delete this.snapshot;
11045 this.data.addAll(r);
11046 this.totalLength = t;
11048 this.fireEvent("datachanged", this);
11050 this.totalLength = Math.max(t, this.data.length+r.length);
11054 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11056 var e = new Roo.data.Record({});
11058 e.set(this.parent.displayField, this.parent.emptyTitle);
11059 e.set(this.parent.valueField, '');
11064 this.fireEvent("load", this, r, options, o);
11065 if(options.callback){
11066 options.callback.call(options.scope || this, r, options, true);
11072 * Loads data from a passed data block. A Reader which understands the format of the data
11073 * must have been configured in the constructor.
11074 * @param {Object} data The data block from which to read the Records. The format of the data expected
11075 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11076 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11078 loadData : function(o, append){
11079 var r = this.reader.readRecords(o);
11080 this.loadRecords(r, {add: append}, true);
11084 * Gets the number of cached records.
11086 * <em>If using paging, this may not be the total size of the dataset. If the data object
11087 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11088 * the data set size</em>
11090 getCount : function(){
11091 return this.data.length || 0;
11095 * Gets the total number of records in the dataset as returned by the server.
11097 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11098 * the dataset size</em>
11100 getTotalCount : function(){
11101 return this.totalLength || 0;
11105 * Returns the sort state of the Store as an object with two properties:
11107 field {String} The name of the field by which the Records are sorted
11108 direction {String} The sort order, "ASC" or "DESC"
11111 getSortState : function(){
11112 return this.sortInfo;
11116 applySort : function(){
11117 if(this.sortInfo && !this.remoteSort){
11118 var s = this.sortInfo, f = s.field;
11119 var st = this.fields.get(f).sortType;
11120 var fn = function(r1, r2){
11121 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11122 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11124 this.data.sort(s.direction, fn);
11125 if(this.snapshot && this.snapshot != this.data){
11126 this.snapshot.sort(s.direction, fn);
11132 * Sets the default sort column and order to be used by the next load operation.
11133 * @param {String} fieldName The name of the field to sort by.
11134 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11136 setDefaultSort : function(field, dir){
11137 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11141 * Sort the Records.
11142 * If remote sorting is used, the sort is performed on the server, and the cache is
11143 * reloaded. If local sorting is used, the cache is sorted internally.
11144 * @param {String} fieldName The name of the field to sort by.
11145 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11147 sort : function(fieldName, dir){
11148 var f = this.fields.get(fieldName);
11150 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11152 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11153 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11158 this.sortToggle[f.name] = dir;
11159 this.sortInfo = {field: f.name, direction: dir};
11160 if(!this.remoteSort){
11162 this.fireEvent("datachanged", this);
11164 this.load(this.lastOptions);
11169 * Calls the specified function for each of the Records in the cache.
11170 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11171 * Returning <em>false</em> aborts and exits the iteration.
11172 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11174 each : function(fn, scope){
11175 this.data.each(fn, scope);
11179 * Gets all records modified since the last commit. Modified records are persisted across load operations
11180 * (e.g., during paging).
11181 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11183 getModifiedRecords : function(){
11184 return this.modified;
11188 createFilterFn : function(property, value, anyMatch){
11189 if(!value.exec){ // not a regex
11190 value = String(value);
11191 if(value.length == 0){
11194 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11196 return function(r){
11197 return value.test(r.data[property]);
11202 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11203 * @param {String} property A field on your records
11204 * @param {Number} start The record index to start at (defaults to 0)
11205 * @param {Number} end The last record index to include (defaults to length - 1)
11206 * @return {Number} The sum
11208 sum : function(property, start, end){
11209 var rs = this.data.items, v = 0;
11210 start = start || 0;
11211 end = (end || end === 0) ? end : rs.length-1;
11213 for(var i = start; i <= end; i++){
11214 v += (rs[i].data[property] || 0);
11220 * Filter the records by a specified property.
11221 * @param {String} field A field on your records
11222 * @param {String/RegExp} value Either a string that the field
11223 * should start with or a RegExp to test against the field
11224 * @param {Boolean} anyMatch True to match any part not just the beginning
11226 filter : function(property, value, anyMatch){
11227 var fn = this.createFilterFn(property, value, anyMatch);
11228 return fn ? this.filterBy(fn) : this.clearFilter();
11232 * Filter by a function. The specified function will be called with each
11233 * record in this data source. If the function returns true the record is included,
11234 * otherwise it is filtered.
11235 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11236 * @param {Object} scope (optional) The scope of the function (defaults to this)
11238 filterBy : function(fn, scope){
11239 this.snapshot = this.snapshot || this.data;
11240 this.data = this.queryBy(fn, scope||this);
11241 this.fireEvent("datachanged", this);
11245 * Query the records by a specified property.
11246 * @param {String} field A field on your records
11247 * @param {String/RegExp} value Either a string that the field
11248 * should start with or a RegExp to test against the field
11249 * @param {Boolean} anyMatch True to match any part not just the beginning
11250 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11252 query : function(property, value, anyMatch){
11253 var fn = this.createFilterFn(property, value, anyMatch);
11254 return fn ? this.queryBy(fn) : this.data.clone();
11258 * Query by a function. The specified function will be called with each
11259 * record in this data source. If the function returns true the record is included
11261 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11262 * @param {Object} scope (optional) The scope of the function (defaults to this)
11263 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11265 queryBy : function(fn, scope){
11266 var data = this.snapshot || this.data;
11267 return data.filterBy(fn, scope||this);
11271 * Collects unique values for a particular dataIndex from this store.
11272 * @param {String} dataIndex The property to collect
11273 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11274 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11275 * @return {Array} An array of the unique values
11277 collect : function(dataIndex, allowNull, bypassFilter){
11278 var d = (bypassFilter === true && this.snapshot) ?
11279 this.snapshot.items : this.data.items;
11280 var v, sv, r = [], l = {};
11281 for(var i = 0, len = d.length; i < len; i++){
11282 v = d[i].data[dataIndex];
11284 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11293 * Revert to a view of the Record cache with no filtering applied.
11294 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11296 clearFilter : function(suppressEvent){
11297 if(this.snapshot && this.snapshot != this.data){
11298 this.data = this.snapshot;
11299 delete this.snapshot;
11300 if(suppressEvent !== true){
11301 this.fireEvent("datachanged", this);
11307 afterEdit : function(record){
11308 if(this.modified.indexOf(record) == -1){
11309 this.modified.push(record);
11311 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11315 afterReject : function(record){
11316 this.modified.remove(record);
11317 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11321 afterCommit : function(record){
11322 this.modified.remove(record);
11323 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11327 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11328 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11330 commitChanges : function(){
11331 var m = this.modified.slice(0);
11332 this.modified = [];
11333 for(var i = 0, len = m.length; i < len; i++){
11339 * Cancel outstanding changes on all changed records.
11341 rejectChanges : function(){
11342 var m = this.modified.slice(0);
11343 this.modified = [];
11344 for(var i = 0, len = m.length; i < len; i++){
11349 onMetaChange : function(meta, rtype, o){
11350 this.recordType = rtype;
11351 this.fields = rtype.prototype.fields;
11352 delete this.snapshot;
11353 this.sortInfo = meta.sortInfo || this.sortInfo;
11354 this.modified = [];
11355 this.fireEvent('metachange', this, this.reader.meta);
11358 moveIndex : function(data, type)
11360 var index = this.indexOf(data);
11362 var newIndex = index + type;
11366 this.insert(newIndex, data);
11371 * Ext JS Library 1.1.1
11372 * Copyright(c) 2006-2007, Ext JS, LLC.
11374 * Originally Released Under LGPL - original licence link has changed is not relivant.
11377 * <script type="text/javascript">
11381 * @class Roo.data.SimpleStore
11382 * @extends Roo.data.Store
11383 * Small helper class to make creating Stores from Array data easier.
11384 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11385 * @cfg {Array} fields An array of field definition objects, or field name strings.
11386 * @cfg {Array} data The multi-dimensional array of data
11388 * @param {Object} config
11390 Roo.data.SimpleStore = function(config){
11391 Roo.data.SimpleStore.superclass.constructor.call(this, {
11393 reader: new Roo.data.ArrayReader({
11396 Roo.data.Record.create(config.fields)
11398 proxy : new Roo.data.MemoryProxy(config.data)
11402 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11404 * Ext JS Library 1.1.1
11405 * Copyright(c) 2006-2007, Ext JS, LLC.
11407 * Originally Released Under LGPL - original licence link has changed is not relivant.
11410 * <script type="text/javascript">
11415 * @extends Roo.data.Store
11416 * @class Roo.data.JsonStore
11417 * Small helper class to make creating Stores for JSON data easier. <br/>
11419 var store = new Roo.data.JsonStore({
11420 url: 'get-images.php',
11422 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11425 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11426 * JsonReader and HttpProxy (unless inline data is provided).</b>
11427 * @cfg {Array} fields An array of field definition objects, or field name strings.
11429 * @param {Object} config
11431 Roo.data.JsonStore = function(c){
11432 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11433 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11434 reader: new Roo.data.JsonReader(c, c.fields)
11437 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11439 * Ext JS Library 1.1.1
11440 * Copyright(c) 2006-2007, Ext JS, LLC.
11442 * Originally Released Under LGPL - original licence link has changed is not relivant.
11445 * <script type="text/javascript">
11449 Roo.data.Field = function(config){
11450 if(typeof config == "string"){
11451 config = {name: config};
11453 Roo.apply(this, config);
11456 this.type = "auto";
11459 var st = Roo.data.SortTypes;
11460 // named sortTypes are supported, here we look them up
11461 if(typeof this.sortType == "string"){
11462 this.sortType = st[this.sortType];
11465 // set default sortType for strings and dates
11466 if(!this.sortType){
11469 this.sortType = st.asUCString;
11472 this.sortType = st.asDate;
11475 this.sortType = st.none;
11480 var stripRe = /[\$,%]/g;
11482 // prebuilt conversion function for this field, instead of
11483 // switching every time we're reading a value
11485 var cv, dateFormat = this.dateFormat;
11490 cv = function(v){ return v; };
11493 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11497 return v !== undefined && v !== null && v !== '' ?
11498 parseInt(String(v).replace(stripRe, ""), 10) : '';
11503 return v !== undefined && v !== null && v !== '' ?
11504 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11509 cv = function(v){ return v === true || v === "true" || v == 1; };
11516 if(v instanceof Date){
11520 if(dateFormat == "timestamp"){
11521 return new Date(v*1000);
11523 return Date.parseDate(v, dateFormat);
11525 var parsed = Date.parse(v);
11526 return parsed ? new Date(parsed) : null;
11535 Roo.data.Field.prototype = {
11543 * Ext JS Library 1.1.1
11544 * Copyright(c) 2006-2007, Ext JS, LLC.
11546 * Originally Released Under LGPL - original licence link has changed is not relivant.
11549 * <script type="text/javascript">
11552 // Base class for reading structured data from a data source. This class is intended to be
11553 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11556 * @class Roo.data.DataReader
11557 * Base class for reading structured data from a data source. This class is intended to be
11558 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11561 Roo.data.DataReader = function(meta, recordType){
11565 this.recordType = recordType instanceof Array ?
11566 Roo.data.Record.create(recordType) : recordType;
11569 Roo.data.DataReader.prototype = {
11571 * Create an empty record
11572 * @param {Object} data (optional) - overlay some values
11573 * @return {Roo.data.Record} record created.
11575 newRow : function(d) {
11577 this.recordType.prototype.fields.each(function(c) {
11579 case 'int' : da[c.name] = 0; break;
11580 case 'date' : da[c.name] = new Date(); break;
11581 case 'float' : da[c.name] = 0.0; break;
11582 case 'boolean' : da[c.name] = false; break;
11583 default : da[c.name] = ""; break;
11587 return new this.recordType(Roo.apply(da, d));
11592 * Ext JS Library 1.1.1
11593 * Copyright(c) 2006-2007, Ext JS, LLC.
11595 * Originally Released Under LGPL - original licence link has changed is not relivant.
11598 * <script type="text/javascript">
11602 * @class Roo.data.DataProxy
11603 * @extends Roo.data.Observable
11604 * This class is an abstract base class for implementations which provide retrieval of
11605 * unformatted data objects.<br>
11607 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11608 * (of the appropriate type which knows how to parse the data object) to provide a block of
11609 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11611 * Custom implementations must implement the load method as described in
11612 * {@link Roo.data.HttpProxy#load}.
11614 Roo.data.DataProxy = function(){
11617 * @event beforeload
11618 * Fires before a network request is made to retrieve a data object.
11619 * @param {Object} This DataProxy object.
11620 * @param {Object} params The params parameter to the load function.
11625 * Fires before the load method's callback is called.
11626 * @param {Object} This DataProxy object.
11627 * @param {Object} o The data object.
11628 * @param {Object} arg The callback argument object passed to the load function.
11632 * @event loadexception
11633 * Fires if an Exception occurs during data retrieval.
11634 * @param {Object} This DataProxy object.
11635 * @param {Object} o The data object.
11636 * @param {Object} arg The callback argument object passed to the load function.
11637 * @param {Object} e The Exception.
11639 loadexception : true
11641 Roo.data.DataProxy.superclass.constructor.call(this);
11644 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11647 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11651 * Ext JS Library 1.1.1
11652 * Copyright(c) 2006-2007, Ext JS, LLC.
11654 * Originally Released Under LGPL - original licence link has changed is not relivant.
11657 * <script type="text/javascript">
11660 * @class Roo.data.MemoryProxy
11661 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11662 * to the Reader when its load method is called.
11664 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11666 Roo.data.MemoryProxy = function(data){
11670 Roo.data.MemoryProxy.superclass.constructor.call(this);
11674 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11677 * Load data from the requested source (in this case an in-memory
11678 * data object passed to the constructor), read the data object into
11679 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11680 * process that block using the passed callback.
11681 * @param {Object} params This parameter is not used by the MemoryProxy class.
11682 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11683 * object into a block of Roo.data.Records.
11684 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11685 * The function must be passed <ul>
11686 * <li>The Record block object</li>
11687 * <li>The "arg" argument from the load function</li>
11688 * <li>A boolean success indicator</li>
11690 * @param {Object} scope The scope in which to call the callback
11691 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11693 load : function(params, reader, callback, scope, arg){
11694 params = params || {};
11697 result = reader.readRecords(this.data);
11699 this.fireEvent("loadexception", this, arg, null, e);
11700 callback.call(scope, null, arg, false);
11703 callback.call(scope, result, arg, true);
11707 update : function(params, records){
11712 * Ext JS Library 1.1.1
11713 * Copyright(c) 2006-2007, Ext JS, LLC.
11715 * Originally Released Under LGPL - original licence link has changed is not relivant.
11718 * <script type="text/javascript">
11721 * @class Roo.data.HttpProxy
11722 * @extends Roo.data.DataProxy
11723 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11724 * configured to reference a certain URL.<br><br>
11726 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11727 * from which the running page was served.<br><br>
11729 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11731 * Be aware that to enable the browser to parse an XML document, the server must set
11732 * the Content-Type header in the HTTP response to "text/xml".
11734 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11735 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11736 * will be used to make the request.
11738 Roo.data.HttpProxy = function(conn){
11739 Roo.data.HttpProxy.superclass.constructor.call(this);
11740 // is conn a conn config or a real conn?
11742 this.useAjax = !conn || !conn.events;
11746 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11747 // thse are take from connection...
11750 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11753 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11754 * extra parameters to each request made by this object. (defaults to undefined)
11757 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11758 * to each request made by this object. (defaults to undefined)
11761 * @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)
11764 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11767 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11773 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11777 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11778 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11779 * a finer-grained basis than the DataProxy events.
11781 getConnection : function(){
11782 return this.useAjax ? Roo.Ajax : this.conn;
11786 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11787 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11788 * process that block using the passed callback.
11789 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11790 * for the request to the remote server.
11791 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11792 * object into a block of Roo.data.Records.
11793 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11794 * The function must be passed <ul>
11795 * <li>The Record block object</li>
11796 * <li>The "arg" argument from the load function</li>
11797 * <li>A boolean success indicator</li>
11799 * @param {Object} scope The scope in which to call the callback
11800 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11802 load : function(params, reader, callback, scope, arg){
11803 if(this.fireEvent("beforeload", this, params) !== false){
11805 params : params || {},
11807 callback : callback,
11812 callback : this.loadResponse,
11816 Roo.applyIf(o, this.conn);
11817 if(this.activeRequest){
11818 Roo.Ajax.abort(this.activeRequest);
11820 this.activeRequest = Roo.Ajax.request(o);
11822 this.conn.request(o);
11825 callback.call(scope||this, null, arg, false);
11830 loadResponse : function(o, success, response){
11831 delete this.activeRequest;
11833 this.fireEvent("loadexception", this, o, response);
11834 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11839 result = o.reader.read(response);
11841 this.fireEvent("loadexception", this, o, response, e);
11842 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11846 this.fireEvent("load", this, o, o.request.arg);
11847 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11851 update : function(dataSet){
11856 updateResponse : function(dataSet){
11861 * Ext JS Library 1.1.1
11862 * Copyright(c) 2006-2007, Ext JS, LLC.
11864 * Originally Released Under LGPL - original licence link has changed is not relivant.
11867 * <script type="text/javascript">
11871 * @class Roo.data.ScriptTagProxy
11872 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11873 * other than the originating domain of the running page.<br><br>
11875 * <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
11876 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11878 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11879 * source code that is used as the source inside a <script> tag.<br><br>
11881 * In order for the browser to process the returned data, the server must wrap the data object
11882 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11883 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11884 * depending on whether the callback name was passed:
11887 boolean scriptTag = false;
11888 String cb = request.getParameter("callback");
11891 response.setContentType("text/javascript");
11893 response.setContentType("application/x-json");
11895 Writer out = response.getWriter();
11897 out.write(cb + "(");
11899 out.print(dataBlock.toJsonString());
11906 * @param {Object} config A configuration object.
11908 Roo.data.ScriptTagProxy = function(config){
11909 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11910 Roo.apply(this, config);
11911 this.head = document.getElementsByTagName("head")[0];
11914 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11916 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11918 * @cfg {String} url The URL from which to request the data object.
11921 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11925 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11926 * the server the name of the callback function set up by the load call to process the returned data object.
11927 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11928 * javascript output which calls this named function passing the data object as its only parameter.
11930 callbackParam : "callback",
11932 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11933 * name to the request.
11938 * Load data from the configured URL, read the data object into
11939 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11940 * process that block using the passed callback.
11941 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11942 * for the request to the remote server.
11943 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11944 * object into a block of Roo.data.Records.
11945 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11946 * The function must be passed <ul>
11947 * <li>The Record block object</li>
11948 * <li>The "arg" argument from the load function</li>
11949 * <li>A boolean success indicator</li>
11951 * @param {Object} scope The scope in which to call the callback
11952 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11954 load : function(params, reader, callback, scope, arg){
11955 if(this.fireEvent("beforeload", this, params) !== false){
11957 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11959 var url = this.url;
11960 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11962 url += "&_dc=" + (new Date().getTime());
11964 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11967 cb : "stcCallback"+transId,
11968 scriptId : "stcScript"+transId,
11972 callback : callback,
11978 window[trans.cb] = function(o){
11979 conn.handleResponse(o, trans);
11982 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11984 if(this.autoAbort !== false){
11988 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11990 var script = document.createElement("script");
11991 script.setAttribute("src", url);
11992 script.setAttribute("type", "text/javascript");
11993 script.setAttribute("id", trans.scriptId);
11994 this.head.appendChild(script);
11996 this.trans = trans;
11998 callback.call(scope||this, null, arg, false);
12003 isLoading : function(){
12004 return this.trans ? true : false;
12008 * Abort the current server request.
12010 abort : function(){
12011 if(this.isLoading()){
12012 this.destroyTrans(this.trans);
12017 destroyTrans : function(trans, isLoaded){
12018 this.head.removeChild(document.getElementById(trans.scriptId));
12019 clearTimeout(trans.timeoutId);
12021 window[trans.cb] = undefined;
12023 delete window[trans.cb];
12026 // if hasn't been loaded, wait for load to remove it to prevent script error
12027 window[trans.cb] = function(){
12028 window[trans.cb] = undefined;
12030 delete window[trans.cb];
12037 handleResponse : function(o, trans){
12038 this.trans = false;
12039 this.destroyTrans(trans, true);
12042 result = trans.reader.readRecords(o);
12044 this.fireEvent("loadexception", this, o, trans.arg, e);
12045 trans.callback.call(trans.scope||window, null, trans.arg, false);
12048 this.fireEvent("load", this, o, trans.arg);
12049 trans.callback.call(trans.scope||window, result, trans.arg, true);
12053 handleFailure : function(trans){
12054 this.trans = false;
12055 this.destroyTrans(trans, false);
12056 this.fireEvent("loadexception", this, null, trans.arg);
12057 trans.callback.call(trans.scope||window, null, trans.arg, false);
12061 * Ext JS Library 1.1.1
12062 * Copyright(c) 2006-2007, Ext JS, LLC.
12064 * Originally Released Under LGPL - original licence link has changed is not relivant.
12067 * <script type="text/javascript">
12071 * @class Roo.data.JsonReader
12072 * @extends Roo.data.DataReader
12073 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12074 * based on mappings in a provided Roo.data.Record constructor.
12076 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12077 * in the reply previously.
12082 var RecordDef = Roo.data.Record.create([
12083 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12084 {name: 'occupation'} // This field will use "occupation" as the mapping.
12086 var myReader = new Roo.data.JsonReader({
12087 totalProperty: "results", // The property which contains the total dataset size (optional)
12088 root: "rows", // The property which contains an Array of row objects
12089 id: "id" // The property within each row object that provides an ID for the record (optional)
12093 * This would consume a JSON file like this:
12095 { 'results': 2, 'rows': [
12096 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12097 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12100 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12101 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12102 * paged from the remote server.
12103 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12104 * @cfg {String} root name of the property which contains the Array of row objects.
12105 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12106 * @cfg {Array} fields Array of field definition objects
12108 * Create a new JsonReader
12109 * @param {Object} meta Metadata configuration options
12110 * @param {Object} recordType Either an Array of field definition objects,
12111 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12113 Roo.data.JsonReader = function(meta, recordType){
12116 // set some defaults:
12117 Roo.applyIf(meta, {
12118 totalProperty: 'total',
12119 successProperty : 'success',
12124 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12126 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12129 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12130 * Used by Store query builder to append _requestMeta to params.
12133 metaFromRemote : false,
12135 * This method is only used by a DataProxy which has retrieved data from a remote server.
12136 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12137 * @return {Object} data A data block which is used by an Roo.data.Store object as
12138 * a cache of Roo.data.Records.
12140 read : function(response){
12141 var json = response.responseText;
12143 var o = /* eval:var:o */ eval("("+json+")");
12145 throw {message: "JsonReader.read: Json object not found"};
12151 this.metaFromRemote = true;
12152 this.meta = o.metaData;
12153 this.recordType = Roo.data.Record.create(o.metaData.fields);
12154 this.onMetaChange(this.meta, this.recordType, o);
12156 return this.readRecords(o);
12159 // private function a store will implement
12160 onMetaChange : function(meta, recordType, o){
12167 simpleAccess: function(obj, subsc) {
12174 getJsonAccessor: function(){
12176 return function(expr) {
12178 return(re.test(expr))
12179 ? new Function("obj", "return obj." + expr)
12184 return Roo.emptyFn;
12189 * Create a data block containing Roo.data.Records from an XML document.
12190 * @param {Object} o An object which contains an Array of row objects in the property specified
12191 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12192 * which contains the total size of the dataset.
12193 * @return {Object} data A data block which is used by an Roo.data.Store object as
12194 * a cache of Roo.data.Records.
12196 readRecords : function(o){
12198 * After any data loads, the raw JSON data is available for further custom processing.
12202 var s = this.meta, Record = this.recordType,
12203 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12205 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12207 if(s.totalProperty) {
12208 this.getTotal = this.getJsonAccessor(s.totalProperty);
12210 if(s.successProperty) {
12211 this.getSuccess = this.getJsonAccessor(s.successProperty);
12213 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12215 var g = this.getJsonAccessor(s.id);
12216 this.getId = function(rec) {
12218 return (r === undefined || r === "") ? null : r;
12221 this.getId = function(){return null;};
12224 for(var jj = 0; jj < fl; jj++){
12226 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12227 this.ef[jj] = this.getJsonAccessor(map);
12231 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12232 if(s.totalProperty){
12233 var vt = parseInt(this.getTotal(o), 10);
12238 if(s.successProperty){
12239 var vs = this.getSuccess(o);
12240 if(vs === false || vs === 'false'){
12245 for(var i = 0; i < c; i++){
12248 var id = this.getId(n);
12249 for(var j = 0; j < fl; j++){
12251 var v = this.ef[j](n);
12253 Roo.log('missing convert for ' + f.name);
12257 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12259 var record = new Record(values, id);
12261 records[i] = record;
12267 totalRecords : totalRecords
12272 * Ext JS Library 1.1.1
12273 * Copyright(c) 2006-2007, Ext JS, LLC.
12275 * Originally Released Under LGPL - original licence link has changed is not relivant.
12278 * <script type="text/javascript">
12282 * @class Roo.data.ArrayReader
12283 * @extends Roo.data.DataReader
12284 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12285 * Each element of that Array represents a row of data fields. The
12286 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12287 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12291 var RecordDef = Roo.data.Record.create([
12292 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12293 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12295 var myReader = new Roo.data.ArrayReader({
12296 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12300 * This would consume an Array like this:
12302 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12304 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12306 * Create a new JsonReader
12307 * @param {Object} meta Metadata configuration options.
12308 * @param {Object} recordType Either an Array of field definition objects
12309 * as specified to {@link Roo.data.Record#create},
12310 * or an {@link Roo.data.Record} object
12311 * created using {@link Roo.data.Record#create}.
12313 Roo.data.ArrayReader = function(meta, recordType){
12314 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12317 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12319 * Create a data block containing Roo.data.Records from an XML document.
12320 * @param {Object} o An Array of row objects which represents the dataset.
12321 * @return {Object} data A data block which is used by an Roo.data.Store object as
12322 * a cache of Roo.data.Records.
12324 readRecords : function(o){
12325 var sid = this.meta ? this.meta.id : null;
12326 var recordType = this.recordType, fields = recordType.prototype.fields;
12329 for(var i = 0; i < root.length; i++){
12332 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12333 for(var j = 0, jlen = fields.length; j < jlen; j++){
12334 var f = fields.items[j];
12335 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12336 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12338 values[f.name] = v;
12340 var record = new recordType(values, id);
12342 records[records.length] = record;
12346 totalRecords : records.length
12355 * @class Roo.bootstrap.ComboBox
12356 * @extends Roo.bootstrap.TriggerField
12357 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12358 * @cfg {Boolean} append (true|false) default false
12359 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12360 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12361 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12362 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12363 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12364 * @cfg {Boolean} animate default true
12365 * @cfg {Boolean} emptyResultText only for touch device
12366 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12367 * @cfg {String} emptyTitle default ''
12369 * Create a new ComboBox.
12370 * @param {Object} config Configuration options
12372 Roo.bootstrap.ComboBox = function(config){
12373 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12377 * Fires when the dropdown list is expanded
12378 * @param {Roo.bootstrap.ComboBox} combo This combo box
12383 * Fires when the dropdown list is collapsed
12384 * @param {Roo.bootstrap.ComboBox} combo This combo box
12388 * @event beforeselect
12389 * Fires before a list item is selected. Return false to cancel the selection.
12390 * @param {Roo.bootstrap.ComboBox} combo This combo box
12391 * @param {Roo.data.Record} record The data record returned from the underlying store
12392 * @param {Number} index The index of the selected item in the dropdown list
12394 'beforeselect' : true,
12397 * Fires when a list item is selected
12398 * @param {Roo.bootstrap.ComboBox} combo This combo box
12399 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12400 * @param {Number} index The index of the selected item in the dropdown list
12404 * @event beforequery
12405 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12406 * The event object passed has these properties:
12407 * @param {Roo.bootstrap.ComboBox} combo This combo box
12408 * @param {String} query The query
12409 * @param {Boolean} forceAll true to force "all" query
12410 * @param {Boolean} cancel true to cancel the query
12411 * @param {Object} e The query event object
12413 'beforequery': true,
12416 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12417 * @param {Roo.bootstrap.ComboBox} combo This combo box
12422 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12423 * @param {Roo.bootstrap.ComboBox} combo This combo box
12424 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12429 * Fires when the remove value from the combobox array
12430 * @param {Roo.bootstrap.ComboBox} combo This combo box
12434 * @event afterremove
12435 * Fires when the remove value from the combobox array
12436 * @param {Roo.bootstrap.ComboBox} combo This combo box
12438 'afterremove' : true,
12440 * @event specialfilter
12441 * Fires when specialfilter
12442 * @param {Roo.bootstrap.ComboBox} combo This combo box
12444 'specialfilter' : true,
12447 * Fires when tick the element
12448 * @param {Roo.bootstrap.ComboBox} combo This combo box
12452 * @event touchviewdisplay
12453 * Fires when touch view require special display (default is using displayField)
12454 * @param {Roo.bootstrap.ComboBox} combo This combo box
12455 * @param {Object} cfg set html .
12457 'touchviewdisplay' : true
12462 this.tickItems = [];
12464 this.selectedIndex = -1;
12465 if(this.mode == 'local'){
12466 if(config.queryDelay === undefined){
12467 this.queryDelay = 10;
12469 if(config.minChars === undefined){
12475 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12478 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12479 * rendering into an Roo.Editor, defaults to false)
12482 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12483 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12486 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12489 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12490 * the dropdown list (defaults to undefined, with no header element)
12494 * @cfg {String/Roo.Template} tpl The template to use to render the output
12498 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12500 listWidth: undefined,
12502 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12503 * mode = 'remote' or 'text' if mode = 'local')
12505 displayField: undefined,
12508 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12509 * mode = 'remote' or 'value' if mode = 'local').
12510 * Note: use of a valueField requires the user make a selection
12511 * in order for a value to be mapped.
12513 valueField: undefined,
12515 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12520 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12521 * field's data value (defaults to the underlying DOM element's name)
12523 hiddenName: undefined,
12525 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12529 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12531 selectedClass: 'active',
12534 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12538 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12539 * anchor positions (defaults to 'tl-bl')
12541 listAlign: 'tl-bl?',
12543 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12547 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12548 * query specified by the allQuery config option (defaults to 'query')
12550 triggerAction: 'query',
12552 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12553 * (defaults to 4, does not apply if editable = false)
12557 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12558 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12562 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12563 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12567 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12568 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12572 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12573 * when editable = true (defaults to false)
12575 selectOnFocus:false,
12577 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12579 queryParam: 'query',
12581 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12582 * when mode = 'remote' (defaults to 'Loading...')
12584 loadingText: 'Loading...',
12586 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12590 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12594 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12595 * traditional select (defaults to true)
12599 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12603 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12607 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12608 * listWidth has a higher value)
12612 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12613 * allow the user to set arbitrary text into the field (defaults to false)
12615 forceSelection:false,
12617 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12618 * if typeAhead = true (defaults to 250)
12620 typeAheadDelay : 250,
12622 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12623 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12625 valueNotFoundText : undefined,
12627 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12629 blockFocus : false,
12632 * @cfg {Boolean} disableClear Disable showing of clear button.
12634 disableClear : false,
12636 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12638 alwaysQuery : false,
12641 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12646 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12648 invalidClass : "has-warning",
12651 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12653 validClass : "has-success",
12656 * @cfg {Boolean} specialFilter (true|false) special filter default false
12658 specialFilter : false,
12661 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12663 mobileTouchView : true,
12666 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12668 useNativeIOS : false,
12670 ios_options : false,
12682 btnPosition : 'right',
12683 triggerList : true,
12684 showToggleBtn : true,
12686 emptyResultText: 'Empty',
12687 triggerText : 'Select',
12690 // element that contains real text value.. (when hidden is used..)
12692 getAutoCreate : function()
12697 * Render classic select for iso
12700 if(Roo.isIOS && this.useNativeIOS){
12701 cfg = this.getAutoCreateNativeIOS();
12709 if(Roo.isTouch && this.mobileTouchView){
12710 cfg = this.getAutoCreateTouchView();
12717 if(!this.tickable){
12718 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12723 * ComboBox with tickable selections
12726 var align = this.labelAlign || this.parentLabelAlign();
12729 cls : 'form-group roo-combobox-tickable' //input-group
12732 var btn_text_select = '';
12733 var btn_text_done = '';
12734 var btn_text_cancel = '';
12736 if (this.btn_text_show) {
12737 btn_text_select = 'Select';
12738 btn_text_done = 'Done';
12739 btn_text_cancel = 'Cancel';
12744 cls : 'tickable-buttons',
12749 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12750 //html : this.triggerText
12751 html: btn_text_select
12757 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12759 html: btn_text_done
12765 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12767 html: btn_text_cancel
12773 buttons.cn.unshift({
12775 cls: 'roo-select2-search-field-input'
12781 Roo.each(buttons.cn, function(c){
12783 c.cls += ' btn-' + _this.size;
12786 if (_this.disabled) {
12797 cls: 'form-hidden-field'
12801 cls: 'roo-select2-choices',
12805 cls: 'roo-select2-search-field',
12816 cls: 'roo-select2-container input-group roo-select2-container-multi',
12821 // cls: 'typeahead typeahead-long dropdown-menu',
12822 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12827 if(this.hasFeedback && !this.allowBlank){
12831 cls: 'glyphicon form-control-feedback'
12834 combobox.cn.push(feedback);
12838 if (align ==='left' && this.fieldLabel.length) {
12840 cfg.cls += ' roo-form-group-label-left';
12845 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12846 tooltip : 'This field is required'
12851 cls : 'control-label',
12852 html : this.fieldLabel
12864 var labelCfg = cfg.cn[1];
12865 var contentCfg = cfg.cn[2];
12868 if(this.indicatorpos == 'right'){
12874 cls : 'control-label',
12878 html : this.fieldLabel
12882 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12883 tooltip : 'This field is required'
12898 labelCfg = cfg.cn[0];
12899 contentCfg = cfg.cn[1];
12903 if(this.labelWidth > 12){
12904 labelCfg.style = "width: " + this.labelWidth + 'px';
12907 if(this.labelWidth < 13 && this.labelmd == 0){
12908 this.labelmd = this.labelWidth;
12911 if(this.labellg > 0){
12912 labelCfg.cls += ' col-lg-' + this.labellg;
12913 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12916 if(this.labelmd > 0){
12917 labelCfg.cls += ' col-md-' + this.labelmd;
12918 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12921 if(this.labelsm > 0){
12922 labelCfg.cls += ' col-sm-' + this.labelsm;
12923 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12926 if(this.labelxs > 0){
12927 labelCfg.cls += ' col-xs-' + this.labelxs;
12928 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12932 } else if ( this.fieldLabel.length) {
12933 // Roo.log(" label");
12937 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12938 tooltip : 'This field is required'
12942 //cls : 'input-group-addon',
12943 html : this.fieldLabel
12948 if(this.indicatorpos == 'right'){
12952 //cls : 'input-group-addon',
12953 html : this.fieldLabel
12957 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12958 tooltip : 'This field is required'
12967 // Roo.log(" no label && no align");
12974 ['xs','sm','md','lg'].map(function(size){
12975 if (settings[size]) {
12976 cfg.cls += ' col-' + size + '-' + settings[size];
12984 _initEventsCalled : false,
12987 initEvents: function()
12989 if (this._initEventsCalled) { // as we call render... prevent looping...
12992 this._initEventsCalled = true;
12995 throw "can not find store for combo";
12998 this.store = Roo.factory(this.store, Roo.data);
12999 this.store.parent = this;
13001 // if we are building from html. then this element is so complex, that we can not really
13002 // use the rendered HTML.
13003 // so we have to trash and replace the previous code.
13004 if (Roo.XComponent.build_from_html) {
13005 // remove this element....
13006 var e = this.el.dom, k=0;
13007 while (e ) { e = e.previousSibling; ++k;}
13012 this.rendered = false;
13014 this.render(this.parent().getChildContainer(true), k);
13017 if(Roo.isIOS && this.useNativeIOS){
13018 this.initIOSView();
13026 if(Roo.isTouch && this.mobileTouchView){
13027 this.initTouchView();
13032 this.initTickableEvents();
13036 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13038 if(this.hiddenName){
13040 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13042 this.hiddenField.dom.value =
13043 this.hiddenValue !== undefined ? this.hiddenValue :
13044 this.value !== undefined ? this.value : '';
13046 // prevent input submission
13047 this.el.dom.removeAttribute('name');
13048 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13053 // this.el.dom.setAttribute('autocomplete', 'off');
13056 var cls = 'x-combo-list';
13058 //this.list = new Roo.Layer({
13059 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13065 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13066 _this.list.setWidth(lw);
13069 this.list.on('mouseover', this.onViewOver, this);
13070 this.list.on('mousemove', this.onViewMove, this);
13071 this.list.on('scroll', this.onViewScroll, this);
13074 this.list.swallowEvent('mousewheel');
13075 this.assetHeight = 0;
13078 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13079 this.assetHeight += this.header.getHeight();
13082 this.innerList = this.list.createChild({cls:cls+'-inner'});
13083 this.innerList.on('mouseover', this.onViewOver, this);
13084 this.innerList.on('mousemove', this.onViewMove, this);
13085 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13087 if(this.allowBlank && !this.pageSize && !this.disableClear){
13088 this.footer = this.list.createChild({cls:cls+'-ft'});
13089 this.pageTb = new Roo.Toolbar(this.footer);
13093 this.footer = this.list.createChild({cls:cls+'-ft'});
13094 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13095 {pageSize: this.pageSize});
13099 if (this.pageTb && this.allowBlank && !this.disableClear) {
13101 this.pageTb.add(new Roo.Toolbar.Fill(), {
13102 cls: 'x-btn-icon x-btn-clear',
13104 handler: function()
13107 _this.clearValue();
13108 _this.onSelect(false, -1);
13113 this.assetHeight += this.footer.getHeight();
13118 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13121 this.view = new Roo.View(this.list, this.tpl, {
13122 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13124 //this.view.wrapEl.setDisplayed(false);
13125 this.view.on('click', this.onViewClick, this);
13128 this.store.on('beforeload', this.onBeforeLoad, this);
13129 this.store.on('load', this.onLoad, this);
13130 this.store.on('loadexception', this.onLoadException, this);
13132 if(this.resizable){
13133 this.resizer = new Roo.Resizable(this.list, {
13134 pinned:true, handles:'se'
13136 this.resizer.on('resize', function(r, w, h){
13137 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13138 this.listWidth = w;
13139 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13140 this.restrictHeight();
13142 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13145 if(!this.editable){
13146 this.editable = true;
13147 this.setEditable(false);
13152 if (typeof(this.events.add.listeners) != 'undefined') {
13154 this.addicon = this.wrap.createChild(
13155 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13157 this.addicon.on('click', function(e) {
13158 this.fireEvent('add', this);
13161 if (typeof(this.events.edit.listeners) != 'undefined') {
13163 this.editicon = this.wrap.createChild(
13164 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13165 if (this.addicon) {
13166 this.editicon.setStyle('margin-left', '40px');
13168 this.editicon.on('click', function(e) {
13170 // we fire even if inothing is selected..
13171 this.fireEvent('edit', this, this.lastData );
13177 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13178 "up" : function(e){
13179 this.inKeyMode = true;
13183 "down" : function(e){
13184 if(!this.isExpanded()){
13185 this.onTriggerClick();
13187 this.inKeyMode = true;
13192 "enter" : function(e){
13193 // this.onViewClick();
13197 if(this.fireEvent("specialkey", this, e)){
13198 this.onViewClick(false);
13204 "esc" : function(e){
13208 "tab" : function(e){
13211 if(this.fireEvent("specialkey", this, e)){
13212 this.onViewClick(false);
13220 doRelay : function(foo, bar, hname){
13221 if(hname == 'down' || this.scope.isExpanded()){
13222 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13231 this.queryDelay = Math.max(this.queryDelay || 10,
13232 this.mode == 'local' ? 10 : 250);
13235 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13237 if(this.typeAhead){
13238 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13240 if(this.editable !== false){
13241 this.inputEl().on("keyup", this.onKeyUp, this);
13243 if(this.forceSelection){
13244 this.inputEl().on('blur', this.doForce, this);
13248 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13249 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13253 initTickableEvents: function()
13257 if(this.hiddenName){
13259 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13261 this.hiddenField.dom.value =
13262 this.hiddenValue !== undefined ? this.hiddenValue :
13263 this.value !== undefined ? this.value : '';
13265 // prevent input submission
13266 this.el.dom.removeAttribute('name');
13267 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13272 // this.list = this.el.select('ul.dropdown-menu',true).first();
13274 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13275 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13276 if(this.triggerList){
13277 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13280 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13281 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13283 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13284 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13286 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13287 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13289 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13290 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13291 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13294 this.cancelBtn.hide();
13299 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13300 _this.list.setWidth(lw);
13303 this.list.on('mouseover', this.onViewOver, this);
13304 this.list.on('mousemove', this.onViewMove, this);
13306 this.list.on('scroll', this.onViewScroll, this);
13309 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>';
13312 this.view = new Roo.View(this.list, this.tpl, {
13313 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13316 //this.view.wrapEl.setDisplayed(false);
13317 this.view.on('click', this.onViewClick, this);
13321 this.store.on('beforeload', this.onBeforeLoad, this);
13322 this.store.on('load', this.onLoad, this);
13323 this.store.on('loadexception', this.onLoadException, this);
13326 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13327 "up" : function(e){
13328 this.inKeyMode = true;
13332 "down" : function(e){
13333 this.inKeyMode = true;
13337 "enter" : function(e){
13338 if(this.fireEvent("specialkey", this, e)){
13339 this.onViewClick(false);
13345 "esc" : function(e){
13346 this.onTickableFooterButtonClick(e, false, false);
13349 "tab" : function(e){
13350 this.fireEvent("specialkey", this, e);
13352 this.onTickableFooterButtonClick(e, false, false);
13359 doRelay : function(e, fn, key){
13360 if(this.scope.isExpanded()){
13361 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13370 this.queryDelay = Math.max(this.queryDelay || 10,
13371 this.mode == 'local' ? 10 : 250);
13374 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13376 if(this.typeAhead){
13377 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13380 if(this.editable !== false){
13381 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13384 this.indicator = this.indicatorEl();
13386 if(this.indicator){
13387 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13388 this.indicator.hide();
13393 onDestroy : function(){
13395 this.view.setStore(null);
13396 this.view.el.removeAllListeners();
13397 this.view.el.remove();
13398 this.view.purgeListeners();
13401 this.list.dom.innerHTML = '';
13405 this.store.un('beforeload', this.onBeforeLoad, this);
13406 this.store.un('load', this.onLoad, this);
13407 this.store.un('loadexception', this.onLoadException, this);
13409 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13413 fireKey : function(e){
13414 if(e.isNavKeyPress() && !this.list.isVisible()){
13415 this.fireEvent("specialkey", this, e);
13420 onResize: function(w, h){
13421 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13423 // if(typeof w != 'number'){
13424 // // we do not handle it!?!?
13427 // var tw = this.trigger.getWidth();
13428 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13429 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13431 // this.inputEl().setWidth( this.adjustWidth('input', x));
13433 // //this.trigger.setStyle('left', x+'px');
13435 // if(this.list && this.listWidth === undefined){
13436 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13437 // this.list.setWidth(lw);
13438 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13446 * Allow or prevent the user from directly editing the field text. If false is passed,
13447 * the user will only be able to select from the items defined in the dropdown list. This method
13448 * is the runtime equivalent of setting the 'editable' config option at config time.
13449 * @param {Boolean} value True to allow the user to directly edit the field text
13451 setEditable : function(value){
13452 if(value == this.editable){
13455 this.editable = value;
13457 this.inputEl().dom.setAttribute('readOnly', true);
13458 this.inputEl().on('mousedown', this.onTriggerClick, this);
13459 this.inputEl().addClass('x-combo-noedit');
13461 this.inputEl().dom.setAttribute('readOnly', false);
13462 this.inputEl().un('mousedown', this.onTriggerClick, this);
13463 this.inputEl().removeClass('x-combo-noedit');
13469 onBeforeLoad : function(combo,opts){
13470 if(!this.hasFocus){
13474 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13476 this.restrictHeight();
13477 this.selectedIndex = -1;
13481 onLoad : function(){
13483 this.hasQuery = false;
13485 if(!this.hasFocus){
13489 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13490 this.loading.hide();
13493 if(this.store.getCount() > 0){
13496 this.restrictHeight();
13497 if(this.lastQuery == this.allQuery){
13498 if(this.editable && !this.tickable){
13499 this.inputEl().dom.select();
13503 !this.selectByValue(this.value, true) &&
13506 !this.store.lastOptions ||
13507 typeof(this.store.lastOptions.add) == 'undefined' ||
13508 this.store.lastOptions.add != true
13511 this.select(0, true);
13514 if(this.autoFocus){
13517 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13518 this.taTask.delay(this.typeAheadDelay);
13522 this.onEmptyResults();
13528 onLoadException : function()
13530 this.hasQuery = false;
13532 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13533 this.loading.hide();
13536 if(this.tickable && this.editable){
13541 // only causes errors at present
13542 //Roo.log(this.store.reader.jsonData);
13543 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13545 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13551 onTypeAhead : function(){
13552 if(this.store.getCount() > 0){
13553 var r = this.store.getAt(0);
13554 var newValue = r.data[this.displayField];
13555 var len = newValue.length;
13556 var selStart = this.getRawValue().length;
13558 if(selStart != len){
13559 this.setRawValue(newValue);
13560 this.selectText(selStart, newValue.length);
13566 onSelect : function(record, index){
13568 if(this.fireEvent('beforeselect', this, record, index) !== false){
13570 this.setFromData(index > -1 ? record.data : false);
13573 this.fireEvent('select', this, record, index);
13578 * Returns the currently selected field value or empty string if no value is set.
13579 * @return {String} value The selected value
13581 getValue : function()
13583 if(Roo.isIOS && this.useNativeIOS){
13584 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13588 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13591 if(this.valueField){
13592 return typeof this.value != 'undefined' ? this.value : '';
13594 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13598 getRawValue : function()
13600 if(Roo.isIOS && this.useNativeIOS){
13601 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13604 var v = this.inputEl().getValue();
13610 * Clears any text/value currently set in the field
13612 clearValue : function(){
13614 if(this.hiddenField){
13615 this.hiddenField.dom.value = '';
13618 this.setRawValue('');
13619 this.lastSelectionText = '';
13620 this.lastData = false;
13622 var close = this.closeTriggerEl();
13633 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13634 * will be displayed in the field. If the value does not match the data value of an existing item,
13635 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13636 * Otherwise the field will be blank (although the value will still be set).
13637 * @param {String} value The value to match
13639 setValue : function(v)
13641 if(Roo.isIOS && this.useNativeIOS){
13642 this.setIOSValue(v);
13652 if(this.valueField){
13653 var r = this.findRecord(this.valueField, v);
13655 text = r.data[this.displayField];
13656 }else if(this.valueNotFoundText !== undefined){
13657 text = this.valueNotFoundText;
13660 this.lastSelectionText = text;
13661 if(this.hiddenField){
13662 this.hiddenField.dom.value = v;
13664 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13667 var close = this.closeTriggerEl();
13670 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13676 * @property {Object} the last set data for the element
13681 * Sets the value of the field based on a object which is related to the record format for the store.
13682 * @param {Object} value the value to set as. or false on reset?
13684 setFromData : function(o){
13691 var dv = ''; // display value
13692 var vv = ''; // value value..
13694 if (this.displayField) {
13695 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13697 // this is an error condition!!!
13698 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13701 if(this.valueField){
13702 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13705 var close = this.closeTriggerEl();
13708 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13711 if(this.hiddenField){
13712 this.hiddenField.dom.value = vv;
13714 this.lastSelectionText = dv;
13715 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13719 // no hidden field.. - we store the value in 'value', but still display
13720 // display field!!!!
13721 this.lastSelectionText = dv;
13722 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13729 reset : function(){
13730 // overridden so that last data is reset..
13737 this.setValue(this.originalValue);
13738 //this.clearInvalid();
13739 this.lastData = false;
13741 this.view.clearSelections();
13747 findRecord : function(prop, value){
13749 if(this.store.getCount() > 0){
13750 this.store.each(function(r){
13751 if(r.data[prop] == value){
13761 getName: function()
13763 // returns hidden if it's set..
13764 if (!this.rendered) {return ''};
13765 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13769 onViewMove : function(e, t){
13770 this.inKeyMode = false;
13774 onViewOver : function(e, t){
13775 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13778 var item = this.view.findItemFromChild(t);
13781 var index = this.view.indexOf(item);
13782 this.select(index, false);
13787 onViewClick : function(view, doFocus, el, e)
13789 var index = this.view.getSelectedIndexes()[0];
13791 var r = this.store.getAt(index);
13795 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13802 Roo.each(this.tickItems, function(v,k){
13804 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13806 _this.tickItems.splice(k, 1);
13808 if(typeof(e) == 'undefined' && view == false){
13809 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13821 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13822 this.tickItems.push(r.data);
13825 if(typeof(e) == 'undefined' && view == false){
13826 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13833 this.onSelect(r, index);
13835 if(doFocus !== false && !this.blockFocus){
13836 this.inputEl().focus();
13841 restrictHeight : function(){
13842 //this.innerList.dom.style.height = '';
13843 //var inner = this.innerList.dom;
13844 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13845 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13846 //this.list.beginUpdate();
13847 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13848 this.list.alignTo(this.inputEl(), this.listAlign);
13849 this.list.alignTo(this.inputEl(), this.listAlign);
13850 //this.list.endUpdate();
13854 onEmptyResults : function(){
13856 if(this.tickable && this.editable){
13857 this.restrictHeight();
13865 * Returns true if the dropdown list is expanded, else false.
13867 isExpanded : function(){
13868 return this.list.isVisible();
13872 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13873 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13874 * @param {String} value The data value of the item to select
13875 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13876 * selected item if it is not currently in view (defaults to true)
13877 * @return {Boolean} True if the value matched an item in the list, else false
13879 selectByValue : function(v, scrollIntoView){
13880 if(v !== undefined && v !== null){
13881 var r = this.findRecord(this.valueField || this.displayField, v);
13883 this.select(this.store.indexOf(r), scrollIntoView);
13891 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13892 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13893 * @param {Number} index The zero-based index of the list item to select
13894 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13895 * selected item if it is not currently in view (defaults to true)
13897 select : function(index, scrollIntoView){
13898 this.selectedIndex = index;
13899 this.view.select(index);
13900 if(scrollIntoView !== false){
13901 var el = this.view.getNode(index);
13903 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13906 this.list.scrollChildIntoView(el, false);
13912 selectNext : function(){
13913 var ct = this.store.getCount();
13915 if(this.selectedIndex == -1){
13917 }else if(this.selectedIndex < ct-1){
13918 this.select(this.selectedIndex+1);
13924 selectPrev : function(){
13925 var ct = this.store.getCount();
13927 if(this.selectedIndex == -1){
13929 }else if(this.selectedIndex != 0){
13930 this.select(this.selectedIndex-1);
13936 onKeyUp : function(e){
13937 if(this.editable !== false && !e.isSpecialKey()){
13938 this.lastKey = e.getKey();
13939 this.dqTask.delay(this.queryDelay);
13944 validateBlur : function(){
13945 return !this.list || !this.list.isVisible();
13949 initQuery : function(){
13951 var v = this.getRawValue();
13953 if(this.tickable && this.editable){
13954 v = this.tickableInputEl().getValue();
13961 doForce : function(){
13962 if(this.inputEl().dom.value.length > 0){
13963 this.inputEl().dom.value =
13964 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13970 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13971 * query allowing the query action to be canceled if needed.
13972 * @param {String} query The SQL query to execute
13973 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13974 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13975 * saved in the current store (defaults to false)
13977 doQuery : function(q, forceAll){
13979 if(q === undefined || q === null){
13984 forceAll: forceAll,
13988 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13993 forceAll = qe.forceAll;
13994 if(forceAll === true || (q.length >= this.minChars)){
13996 this.hasQuery = true;
13998 if(this.lastQuery != q || this.alwaysQuery){
13999 this.lastQuery = q;
14000 if(this.mode == 'local'){
14001 this.selectedIndex = -1;
14003 this.store.clearFilter();
14006 if(this.specialFilter){
14007 this.fireEvent('specialfilter', this);
14012 this.store.filter(this.displayField, q);
14015 this.store.fireEvent("datachanged", this.store);
14022 this.store.baseParams[this.queryParam] = q;
14024 var options = {params : this.getParams(q)};
14027 options.add = true;
14028 options.params.start = this.page * this.pageSize;
14031 this.store.load(options);
14034 * this code will make the page width larger, at the beginning, the list not align correctly,
14035 * we should expand the list on onLoad
14036 * so command out it
14041 this.selectedIndex = -1;
14046 this.loadNext = false;
14050 getParams : function(q){
14052 //p[this.queryParam] = q;
14056 p.limit = this.pageSize;
14062 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14064 collapse : function(){
14065 if(!this.isExpanded()){
14071 this.hasFocus = false;
14075 this.cancelBtn.hide();
14076 this.trigger.show();
14079 this.tickableInputEl().dom.value = '';
14080 this.tickableInputEl().blur();
14085 Roo.get(document).un('mousedown', this.collapseIf, this);
14086 Roo.get(document).un('mousewheel', this.collapseIf, this);
14087 if (!this.editable) {
14088 Roo.get(document).un('keydown', this.listKeyPress, this);
14090 this.fireEvent('collapse', this);
14096 collapseIf : function(e){
14097 var in_combo = e.within(this.el);
14098 var in_list = e.within(this.list);
14099 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14101 if (in_combo || in_list || is_list) {
14102 //e.stopPropagation();
14107 this.onTickableFooterButtonClick(e, false, false);
14115 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14117 expand : function(){
14119 if(this.isExpanded() || !this.hasFocus){
14123 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14124 this.list.setWidth(lw);
14130 this.restrictHeight();
14134 this.tickItems = Roo.apply([], this.item);
14137 this.cancelBtn.show();
14138 this.trigger.hide();
14141 this.tickableInputEl().focus();
14146 Roo.get(document).on('mousedown', this.collapseIf, this);
14147 Roo.get(document).on('mousewheel', this.collapseIf, this);
14148 if (!this.editable) {
14149 Roo.get(document).on('keydown', this.listKeyPress, this);
14152 this.fireEvent('expand', this);
14156 // Implements the default empty TriggerField.onTriggerClick function
14157 onTriggerClick : function(e)
14159 Roo.log('trigger click');
14161 if(this.disabled || !this.triggerList){
14166 this.loadNext = false;
14168 if(this.isExpanded()){
14170 if (!this.blockFocus) {
14171 this.inputEl().focus();
14175 this.hasFocus = true;
14176 if(this.triggerAction == 'all') {
14177 this.doQuery(this.allQuery, true);
14179 this.doQuery(this.getRawValue());
14181 if (!this.blockFocus) {
14182 this.inputEl().focus();
14187 onTickableTriggerClick : function(e)
14194 this.loadNext = false;
14195 this.hasFocus = true;
14197 if(this.triggerAction == 'all') {
14198 this.doQuery(this.allQuery, true);
14200 this.doQuery(this.getRawValue());
14204 onSearchFieldClick : function(e)
14206 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14207 this.onTickableFooterButtonClick(e, false, false);
14211 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14216 this.loadNext = false;
14217 this.hasFocus = true;
14219 if(this.triggerAction == 'all') {
14220 this.doQuery(this.allQuery, true);
14222 this.doQuery(this.getRawValue());
14226 listKeyPress : function(e)
14228 //Roo.log('listkeypress');
14229 // scroll to first matching element based on key pres..
14230 if (e.isSpecialKey()) {
14233 var k = String.fromCharCode(e.getKey()).toUpperCase();
14236 var csel = this.view.getSelectedNodes();
14237 var cselitem = false;
14239 var ix = this.view.indexOf(csel[0]);
14240 cselitem = this.store.getAt(ix);
14241 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14247 this.store.each(function(v) {
14249 // start at existing selection.
14250 if (cselitem.id == v.id) {
14256 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14257 match = this.store.indexOf(v);
14263 if (match === false) {
14264 return true; // no more action?
14267 this.view.select(match);
14268 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14269 sn.scrollIntoView(sn.dom.parentNode, false);
14272 onViewScroll : function(e, t){
14274 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){
14278 this.hasQuery = true;
14280 this.loading = this.list.select('.loading', true).first();
14282 if(this.loading === null){
14283 this.list.createChild({
14285 cls: 'loading roo-select2-more-results roo-select2-active',
14286 html: 'Loading more results...'
14289 this.loading = this.list.select('.loading', true).first();
14291 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14293 this.loading.hide();
14296 this.loading.show();
14301 this.loadNext = true;
14303 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14308 addItem : function(o)
14310 var dv = ''; // display value
14312 if (this.displayField) {
14313 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14315 // this is an error condition!!!
14316 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14323 var choice = this.choices.createChild({
14325 cls: 'roo-select2-search-choice',
14334 cls: 'roo-select2-search-choice-close fa fa-times',
14339 }, this.searchField);
14341 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14343 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14351 this.inputEl().dom.value = '';
14356 onRemoveItem : function(e, _self, o)
14358 e.preventDefault();
14360 this.lastItem = Roo.apply([], this.item);
14362 var index = this.item.indexOf(o.data) * 1;
14365 Roo.log('not this item?!');
14369 this.item.splice(index, 1);
14374 this.fireEvent('remove', this, e);
14380 syncValue : function()
14382 if(!this.item.length){
14389 Roo.each(this.item, function(i){
14390 if(_this.valueField){
14391 value.push(i[_this.valueField]);
14398 this.value = value.join(',');
14400 if(this.hiddenField){
14401 this.hiddenField.dom.value = this.value;
14404 this.store.fireEvent("datachanged", this.store);
14409 clearItem : function()
14411 if(!this.multiple){
14417 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14425 if(this.tickable && !Roo.isTouch){
14426 this.view.refresh();
14430 inputEl: function ()
14432 if(Roo.isIOS && this.useNativeIOS){
14433 return this.el.select('select.roo-ios-select', true).first();
14436 if(Roo.isTouch && this.mobileTouchView){
14437 return this.el.select('input.form-control',true).first();
14441 return this.searchField;
14444 return this.el.select('input.form-control',true).first();
14447 onTickableFooterButtonClick : function(e, btn, el)
14449 e.preventDefault();
14451 this.lastItem = Roo.apply([], this.item);
14453 if(btn && btn.name == 'cancel'){
14454 this.tickItems = Roo.apply([], this.item);
14463 Roo.each(this.tickItems, function(o){
14471 validate : function()
14473 var v = this.getRawValue();
14476 v = this.getValue();
14479 if(this.disabled || this.allowBlank || v.length){
14484 this.markInvalid();
14488 tickableInputEl : function()
14490 if(!this.tickable || !this.editable){
14491 return this.inputEl();
14494 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14498 getAutoCreateTouchView : function()
14503 cls: 'form-group' //input-group
14509 type : this.inputType,
14510 cls : 'form-control x-combo-noedit',
14511 autocomplete: 'new-password',
14512 placeholder : this.placeholder || '',
14517 input.name = this.name;
14521 input.cls += ' input-' + this.size;
14524 if (this.disabled) {
14525 input.disabled = true;
14536 inputblock.cls += ' input-group';
14538 inputblock.cn.unshift({
14540 cls : 'input-group-addon',
14545 if(this.removable && !this.multiple){
14546 inputblock.cls += ' roo-removable';
14548 inputblock.cn.push({
14551 cls : 'roo-combo-removable-btn close'
14555 if(this.hasFeedback && !this.allowBlank){
14557 inputblock.cls += ' has-feedback';
14559 inputblock.cn.push({
14561 cls: 'glyphicon form-control-feedback'
14568 inputblock.cls += (this.before) ? '' : ' input-group';
14570 inputblock.cn.push({
14572 cls : 'input-group-addon',
14583 cls: 'form-hidden-field'
14597 cls: 'form-hidden-field'
14601 cls: 'roo-select2-choices',
14605 cls: 'roo-select2-search-field',
14618 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14624 if(!this.multiple && this.showToggleBtn){
14631 if (this.caret != false) {
14634 cls: 'fa fa-' + this.caret
14641 cls : 'input-group-addon btn dropdown-toggle',
14646 cls: 'combobox-clear',
14660 combobox.cls += ' roo-select2-container-multi';
14663 var align = this.labelAlign || this.parentLabelAlign();
14665 if (align ==='left' && this.fieldLabel.length) {
14670 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14671 tooltip : 'This field is required'
14675 cls : 'control-label',
14676 html : this.fieldLabel
14687 var labelCfg = cfg.cn[1];
14688 var contentCfg = cfg.cn[2];
14691 if(this.indicatorpos == 'right'){
14695 cls : 'control-label',
14696 html : this.fieldLabel,
14700 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14701 tooltip : 'This field is required'
14714 labelCfg = cfg.cn[0];
14715 contentCfg = cfg.cn[2];
14717 if(this.labelWidth > 12){
14718 labelCfg.style = "width: " + this.labelWidth + 'px';
14721 if(this.labelWidth < 13 && this.labelmd == 0){
14722 this.labelmd = this.labelWidth;
14725 if(this.labellg > 0){
14726 labelCfg.cls += ' col-lg-' + this.labellg;
14727 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14730 if(this.labelmd > 0){
14731 labelCfg.cls += ' col-md-' + this.labelmd;
14732 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14735 if(this.labelsm > 0){
14736 labelCfg.cls += ' col-sm-' + this.labelsm;
14737 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14740 if(this.labelxs > 0){
14741 labelCfg.cls += ' col-xs-' + this.labelxs;
14742 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14746 } else if ( this.fieldLabel.length) {
14750 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14751 tooltip : 'This field is required'
14755 cls : 'control-label',
14756 html : this.fieldLabel
14767 if(this.indicatorpos == 'right'){
14771 cls : 'control-label',
14772 html : this.fieldLabel,
14776 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14777 tooltip : 'This field is required'
14794 var settings = this;
14796 ['xs','sm','md','lg'].map(function(size){
14797 if (settings[size]) {
14798 cfg.cls += ' col-' + size + '-' + settings[size];
14805 initTouchView : function()
14807 this.renderTouchView();
14809 this.touchViewEl.on('scroll', function(){
14810 this.el.dom.scrollTop = 0;
14813 this.originalValue = this.getValue();
14815 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14817 this.inputEl().on("click", this.showTouchView, this);
14818 if (this.triggerEl) {
14819 this.triggerEl.on("click", this.showTouchView, this);
14823 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14824 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14826 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14828 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14829 this.store.on('load', this.onTouchViewLoad, this);
14830 this.store.on('loadexception', this.onTouchViewLoadException, this);
14832 if(this.hiddenName){
14834 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14836 this.hiddenField.dom.value =
14837 this.hiddenValue !== undefined ? this.hiddenValue :
14838 this.value !== undefined ? this.value : '';
14840 this.el.dom.removeAttribute('name');
14841 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14845 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14846 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14849 if(this.removable && !this.multiple){
14850 var close = this.closeTriggerEl();
14852 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14853 close.on('click', this.removeBtnClick, this, close);
14857 * fix the bug in Safari iOS8
14859 this.inputEl().on("focus", function(e){
14860 document.activeElement.blur();
14868 renderTouchView : function()
14870 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14871 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14873 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14874 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14876 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14877 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14878 this.touchViewBodyEl.setStyle('overflow', 'auto');
14880 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14881 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14883 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14884 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14888 showTouchView : function()
14894 this.touchViewHeaderEl.hide();
14896 if(this.modalTitle.length){
14897 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14898 this.touchViewHeaderEl.show();
14901 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14902 this.touchViewEl.show();
14904 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14905 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14906 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14908 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14910 if(this.modalTitle.length){
14911 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14914 this.touchViewBodyEl.setHeight(bodyHeight);
14918 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14920 this.touchViewEl.addClass('in');
14923 this.doTouchViewQuery();
14927 hideTouchView : function()
14929 this.touchViewEl.removeClass('in');
14933 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14935 this.touchViewEl.setStyle('display', 'none');
14940 setTouchViewValue : function()
14947 Roo.each(this.tickItems, function(o){
14952 this.hideTouchView();
14955 doTouchViewQuery : function()
14964 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14968 if(!this.alwaysQuery || this.mode == 'local'){
14969 this.onTouchViewLoad();
14976 onTouchViewBeforeLoad : function(combo,opts)
14982 onTouchViewLoad : function()
14984 if(this.store.getCount() < 1){
14985 this.onTouchViewEmptyResults();
14989 this.clearTouchView();
14991 var rawValue = this.getRawValue();
14993 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14995 this.tickItems = [];
14997 this.store.data.each(function(d, rowIndex){
14998 var row = this.touchViewListGroup.createChild(template);
15000 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15001 row.addClass(d.data.cls);
15004 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15007 html : d.data[this.displayField]
15010 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15011 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15014 row.removeClass('selected');
15015 if(!this.multiple && this.valueField &&
15016 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15019 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15020 row.addClass('selected');
15023 if(this.multiple && this.valueField &&
15024 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15028 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15029 this.tickItems.push(d.data);
15032 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15036 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15038 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15040 if(this.modalTitle.length){
15041 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15044 var listHeight = this.touchViewListGroup.getHeight();
15048 if(firstChecked && listHeight > bodyHeight){
15049 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15054 onTouchViewLoadException : function()
15056 this.hideTouchView();
15059 onTouchViewEmptyResults : function()
15061 this.clearTouchView();
15063 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15065 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15069 clearTouchView : function()
15071 this.touchViewListGroup.dom.innerHTML = '';
15074 onTouchViewClick : function(e, el, o)
15076 e.preventDefault();
15079 var rowIndex = o.rowIndex;
15081 var r = this.store.getAt(rowIndex);
15083 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15085 if(!this.multiple){
15086 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15087 c.dom.removeAttribute('checked');
15090 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15092 this.setFromData(r.data);
15094 var close = this.closeTriggerEl();
15100 this.hideTouchView();
15102 this.fireEvent('select', this, r, rowIndex);
15107 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15108 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15109 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15113 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15114 this.addItem(r.data);
15115 this.tickItems.push(r.data);
15119 getAutoCreateNativeIOS : function()
15122 cls: 'form-group' //input-group,
15127 cls : 'roo-ios-select'
15131 combobox.name = this.name;
15134 if (this.disabled) {
15135 combobox.disabled = true;
15138 var settings = this;
15140 ['xs','sm','md','lg'].map(function(size){
15141 if (settings[size]) {
15142 cfg.cls += ' col-' + size + '-' + settings[size];
15152 initIOSView : function()
15154 this.store.on('load', this.onIOSViewLoad, this);
15159 onIOSViewLoad : function()
15161 if(this.store.getCount() < 1){
15165 this.clearIOSView();
15167 if(this.allowBlank) {
15169 var default_text = '-- SELECT --';
15171 var opt = this.inputEl().createChild({
15174 html : default_text
15178 o[this.valueField] = 0;
15179 o[this.displayField] = default_text;
15181 this.ios_options.push({
15188 this.store.data.each(function(d, rowIndex){
15192 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15193 html = d.data[this.displayField];
15198 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15199 value = d.data[this.valueField];
15208 if(this.value == d.data[this.valueField]){
15209 option['selected'] = true;
15212 var opt = this.inputEl().createChild(option);
15214 this.ios_options.push({
15221 this.inputEl().on('change', function(){
15222 this.fireEvent('select', this);
15227 clearIOSView: function()
15229 this.inputEl().dom.innerHTML = '';
15231 this.ios_options = [];
15234 setIOSValue: function(v)
15238 if(!this.ios_options){
15242 Roo.each(this.ios_options, function(opts){
15244 opts.el.dom.removeAttribute('selected');
15246 if(opts.data[this.valueField] != v){
15250 opts.el.dom.setAttribute('selected', true);
15256 * @cfg {Boolean} grow
15260 * @cfg {Number} growMin
15264 * @cfg {Number} growMax
15273 Roo.apply(Roo.bootstrap.ComboBox, {
15277 cls: 'modal-header',
15299 cls: 'list-group-item',
15303 cls: 'roo-combobox-list-group-item-value'
15307 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15321 listItemCheckbox : {
15323 cls: 'list-group-item',
15327 cls: 'roo-combobox-list-group-item-value'
15331 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15347 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15352 cls: 'modal-footer',
15360 cls: 'col-xs-6 text-left',
15363 cls: 'btn btn-danger roo-touch-view-cancel',
15369 cls: 'col-xs-6 text-right',
15372 cls: 'btn btn-success roo-touch-view-ok',
15383 Roo.apply(Roo.bootstrap.ComboBox, {
15385 touchViewTemplate : {
15387 cls: 'modal fade roo-combobox-touch-view',
15391 cls: 'modal-dialog',
15392 style : 'position:fixed', // we have to fix position....
15396 cls: 'modal-content',
15398 Roo.bootstrap.ComboBox.header,
15399 Roo.bootstrap.ComboBox.body,
15400 Roo.bootstrap.ComboBox.footer
15409 * Ext JS Library 1.1.1
15410 * Copyright(c) 2006-2007, Ext JS, LLC.
15412 * Originally Released Under LGPL - original licence link has changed is not relivant.
15415 * <script type="text/javascript">
15420 * @extends Roo.util.Observable
15421 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15422 * This class also supports single and multi selection modes. <br>
15423 * Create a data model bound view:
15425 var store = new Roo.data.Store(...);
15427 var view = new Roo.View({
15429 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15431 singleSelect: true,
15432 selectedClass: "ydataview-selected",
15436 // listen for node click?
15437 view.on("click", function(vw, index, node, e){
15438 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15442 dataModel.load("foobar.xml");
15444 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15446 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15447 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15449 * Note: old style constructor is still suported (container, template, config)
15452 * Create a new View
15453 * @param {Object} config The config object
15456 Roo.View = function(config, depreciated_tpl, depreciated_config){
15458 this.parent = false;
15460 if (typeof(depreciated_tpl) == 'undefined') {
15461 // new way.. - universal constructor.
15462 Roo.apply(this, config);
15463 this.el = Roo.get(this.el);
15466 this.el = Roo.get(config);
15467 this.tpl = depreciated_tpl;
15468 Roo.apply(this, depreciated_config);
15470 this.wrapEl = this.el.wrap().wrap();
15471 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15474 if(typeof(this.tpl) == "string"){
15475 this.tpl = new Roo.Template(this.tpl);
15477 // support xtype ctors..
15478 this.tpl = new Roo.factory(this.tpl, Roo);
15482 this.tpl.compile();
15487 * @event beforeclick
15488 * Fires before a click is processed. Returns false to cancel the default action.
15489 * @param {Roo.View} this
15490 * @param {Number} index The index of the target node
15491 * @param {HTMLElement} node The target node
15492 * @param {Roo.EventObject} e The raw event object
15494 "beforeclick" : true,
15497 * Fires when a template node is clicked.
15498 * @param {Roo.View} this
15499 * @param {Number} index The index of the target node
15500 * @param {HTMLElement} node The target node
15501 * @param {Roo.EventObject} e The raw event object
15506 * Fires when a template node is double clicked.
15507 * @param {Roo.View} this
15508 * @param {Number} index The index of the target node
15509 * @param {HTMLElement} node The target node
15510 * @param {Roo.EventObject} e The raw event object
15514 * @event contextmenu
15515 * Fires when a template node is right clicked.
15516 * @param {Roo.View} this
15517 * @param {Number} index The index of the target node
15518 * @param {HTMLElement} node The target node
15519 * @param {Roo.EventObject} e The raw event object
15521 "contextmenu" : true,
15523 * @event selectionchange
15524 * Fires when the selected nodes change.
15525 * @param {Roo.View} this
15526 * @param {Array} selections Array of the selected nodes
15528 "selectionchange" : true,
15531 * @event beforeselect
15532 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15533 * @param {Roo.View} this
15534 * @param {HTMLElement} node The node to be selected
15535 * @param {Array} selections Array of currently selected nodes
15537 "beforeselect" : true,
15539 * @event preparedata
15540 * Fires on every row to render, to allow you to change the data.
15541 * @param {Roo.View} this
15542 * @param {Object} data to be rendered (change this)
15544 "preparedata" : true
15552 "click": this.onClick,
15553 "dblclick": this.onDblClick,
15554 "contextmenu": this.onContextMenu,
15558 this.selections = [];
15560 this.cmp = new Roo.CompositeElementLite([]);
15562 this.store = Roo.factory(this.store, Roo.data);
15563 this.setStore(this.store, true);
15566 if ( this.footer && this.footer.xtype) {
15568 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15570 this.footer.dataSource = this.store;
15571 this.footer.container = fctr;
15572 this.footer = Roo.factory(this.footer, Roo);
15573 fctr.insertFirst(this.el);
15575 // this is a bit insane - as the paging toolbar seems to detach the el..
15576 // dom.parentNode.parentNode.parentNode
15577 // they get detached?
15581 Roo.View.superclass.constructor.call(this);
15586 Roo.extend(Roo.View, Roo.util.Observable, {
15589 * @cfg {Roo.data.Store} store Data store to load data from.
15594 * @cfg {String|Roo.Element} el The container element.
15599 * @cfg {String|Roo.Template} tpl The template used by this View
15603 * @cfg {String} dataName the named area of the template to use as the data area
15604 * Works with domtemplates roo-name="name"
15608 * @cfg {String} selectedClass The css class to add to selected nodes
15610 selectedClass : "x-view-selected",
15612 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15617 * @cfg {String} text to display on mask (default Loading)
15621 * @cfg {Boolean} multiSelect Allow multiple selection
15623 multiSelect : false,
15625 * @cfg {Boolean} singleSelect Allow single selection
15627 singleSelect: false,
15630 * @cfg {Boolean} toggleSelect - selecting
15632 toggleSelect : false,
15635 * @cfg {Boolean} tickable - selecting
15640 * Returns the element this view is bound to.
15641 * @return {Roo.Element}
15643 getEl : function(){
15644 return this.wrapEl;
15650 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15652 refresh : function(){
15653 //Roo.log('refresh');
15656 // if we are using something like 'domtemplate', then
15657 // the what gets used is:
15658 // t.applySubtemplate(NAME, data, wrapping data..)
15659 // the outer template then get' applied with
15660 // the store 'extra data'
15661 // and the body get's added to the
15662 // roo-name="data" node?
15663 // <span class='roo-tpl-{name}'></span> ?????
15667 this.clearSelections();
15668 this.el.update("");
15670 var records = this.store.getRange();
15671 if(records.length < 1) {
15673 // is this valid?? = should it render a template??
15675 this.el.update(this.emptyText);
15679 if (this.dataName) {
15680 this.el.update(t.apply(this.store.meta)); //????
15681 el = this.el.child('.roo-tpl-' + this.dataName);
15684 for(var i = 0, len = records.length; i < len; i++){
15685 var data = this.prepareData(records[i].data, i, records[i]);
15686 this.fireEvent("preparedata", this, data, i, records[i]);
15688 var d = Roo.apply({}, data);
15691 Roo.apply(d, {'roo-id' : Roo.id()});
15695 Roo.each(this.parent.item, function(item){
15696 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15699 Roo.apply(d, {'roo-data-checked' : 'checked'});
15703 html[html.length] = Roo.util.Format.trim(
15705 t.applySubtemplate(this.dataName, d, this.store.meta) :
15712 el.update(html.join(""));
15713 this.nodes = el.dom.childNodes;
15714 this.updateIndexes(0);
15719 * Function to override to reformat the data that is sent to
15720 * the template for each node.
15721 * DEPRICATED - use the preparedata event handler.
15722 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15723 * a JSON object for an UpdateManager bound view).
15725 prepareData : function(data, index, record)
15727 this.fireEvent("preparedata", this, data, index, record);
15731 onUpdate : function(ds, record){
15732 // Roo.log('on update');
15733 this.clearSelections();
15734 var index = this.store.indexOf(record);
15735 var n = this.nodes[index];
15736 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15737 n.parentNode.removeChild(n);
15738 this.updateIndexes(index, index);
15744 onAdd : function(ds, records, index)
15746 //Roo.log(['on Add', ds, records, index] );
15747 this.clearSelections();
15748 if(this.nodes.length == 0){
15752 var n = this.nodes[index];
15753 for(var i = 0, len = records.length; i < len; i++){
15754 var d = this.prepareData(records[i].data, i, records[i]);
15756 this.tpl.insertBefore(n, d);
15759 this.tpl.append(this.el, d);
15762 this.updateIndexes(index);
15765 onRemove : function(ds, record, index){
15766 // Roo.log('onRemove');
15767 this.clearSelections();
15768 var el = this.dataName ?
15769 this.el.child('.roo-tpl-' + this.dataName) :
15772 el.dom.removeChild(this.nodes[index]);
15773 this.updateIndexes(index);
15777 * Refresh an individual node.
15778 * @param {Number} index
15780 refreshNode : function(index){
15781 this.onUpdate(this.store, this.store.getAt(index));
15784 updateIndexes : function(startIndex, endIndex){
15785 var ns = this.nodes;
15786 startIndex = startIndex || 0;
15787 endIndex = endIndex || ns.length - 1;
15788 for(var i = startIndex; i <= endIndex; i++){
15789 ns[i].nodeIndex = i;
15794 * Changes the data store this view uses and refresh the view.
15795 * @param {Store} store
15797 setStore : function(store, initial){
15798 if(!initial && this.store){
15799 this.store.un("datachanged", this.refresh);
15800 this.store.un("add", this.onAdd);
15801 this.store.un("remove", this.onRemove);
15802 this.store.un("update", this.onUpdate);
15803 this.store.un("clear", this.refresh);
15804 this.store.un("beforeload", this.onBeforeLoad);
15805 this.store.un("load", this.onLoad);
15806 this.store.un("loadexception", this.onLoad);
15810 store.on("datachanged", this.refresh, this);
15811 store.on("add", this.onAdd, this);
15812 store.on("remove", this.onRemove, this);
15813 store.on("update", this.onUpdate, this);
15814 store.on("clear", this.refresh, this);
15815 store.on("beforeload", this.onBeforeLoad, this);
15816 store.on("load", this.onLoad, this);
15817 store.on("loadexception", this.onLoad, this);
15825 * onbeforeLoad - masks the loading area.
15828 onBeforeLoad : function(store,opts)
15830 //Roo.log('onBeforeLoad');
15832 this.el.update("");
15834 this.el.mask(this.mask ? this.mask : "Loading" );
15836 onLoad : function ()
15843 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15844 * @param {HTMLElement} node
15845 * @return {HTMLElement} The template node
15847 findItemFromChild : function(node){
15848 var el = this.dataName ?
15849 this.el.child('.roo-tpl-' + this.dataName,true) :
15852 if(!node || node.parentNode == el){
15855 var p = node.parentNode;
15856 while(p && p != el){
15857 if(p.parentNode == el){
15866 onClick : function(e){
15867 var item = this.findItemFromChild(e.getTarget());
15869 var index = this.indexOf(item);
15870 if(this.onItemClick(item, index, e) !== false){
15871 this.fireEvent("click", this, index, item, e);
15874 this.clearSelections();
15879 onContextMenu : function(e){
15880 var item = this.findItemFromChild(e.getTarget());
15882 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15887 onDblClick : function(e){
15888 var item = this.findItemFromChild(e.getTarget());
15890 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15894 onItemClick : function(item, index, e)
15896 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15899 if (this.toggleSelect) {
15900 var m = this.isSelected(item) ? 'unselect' : 'select';
15903 _t[m](item, true, false);
15906 if(this.multiSelect || this.singleSelect){
15907 if(this.multiSelect && e.shiftKey && this.lastSelection){
15908 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15910 this.select(item, this.multiSelect && e.ctrlKey);
15911 this.lastSelection = item;
15914 if(!this.tickable){
15915 e.preventDefault();
15923 * Get the number of selected nodes.
15926 getSelectionCount : function(){
15927 return this.selections.length;
15931 * Get the currently selected nodes.
15932 * @return {Array} An array of HTMLElements
15934 getSelectedNodes : function(){
15935 return this.selections;
15939 * Get the indexes of the selected nodes.
15942 getSelectedIndexes : function(){
15943 var indexes = [], s = this.selections;
15944 for(var i = 0, len = s.length; i < len; i++){
15945 indexes.push(s[i].nodeIndex);
15951 * Clear all selections
15952 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15954 clearSelections : function(suppressEvent){
15955 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15956 this.cmp.elements = this.selections;
15957 this.cmp.removeClass(this.selectedClass);
15958 this.selections = [];
15959 if(!suppressEvent){
15960 this.fireEvent("selectionchange", this, this.selections);
15966 * Returns true if the passed node is selected
15967 * @param {HTMLElement/Number} node The node or node index
15968 * @return {Boolean}
15970 isSelected : function(node){
15971 var s = this.selections;
15975 node = this.getNode(node);
15976 return s.indexOf(node) !== -1;
15981 * @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
15982 * @param {Boolean} keepExisting (optional) true to keep existing selections
15983 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15985 select : function(nodeInfo, keepExisting, suppressEvent){
15986 if(nodeInfo instanceof Array){
15988 this.clearSelections(true);
15990 for(var i = 0, len = nodeInfo.length; i < len; i++){
15991 this.select(nodeInfo[i], true, true);
15995 var node = this.getNode(nodeInfo);
15996 if(!node || this.isSelected(node)){
15997 return; // already selected.
16000 this.clearSelections(true);
16003 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16004 Roo.fly(node).addClass(this.selectedClass);
16005 this.selections.push(node);
16006 if(!suppressEvent){
16007 this.fireEvent("selectionchange", this, this.selections);
16015 * @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
16016 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16017 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16019 unselect : function(nodeInfo, keepExisting, suppressEvent)
16021 if(nodeInfo instanceof Array){
16022 Roo.each(this.selections, function(s) {
16023 this.unselect(s, nodeInfo);
16027 var node = this.getNode(nodeInfo);
16028 if(!node || !this.isSelected(node)){
16029 //Roo.log("not selected");
16030 return; // not selected.
16034 Roo.each(this.selections, function(s) {
16036 Roo.fly(node).removeClass(this.selectedClass);
16043 this.selections= ns;
16044 this.fireEvent("selectionchange", this, this.selections);
16048 * Gets a template node.
16049 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16050 * @return {HTMLElement} The node or null if it wasn't found
16052 getNode : function(nodeInfo){
16053 if(typeof nodeInfo == "string"){
16054 return document.getElementById(nodeInfo);
16055 }else if(typeof nodeInfo == "number"){
16056 return this.nodes[nodeInfo];
16062 * Gets a range template nodes.
16063 * @param {Number} startIndex
16064 * @param {Number} endIndex
16065 * @return {Array} An array of nodes
16067 getNodes : function(start, end){
16068 var ns = this.nodes;
16069 start = start || 0;
16070 end = typeof end == "undefined" ? ns.length - 1 : end;
16073 for(var i = start; i <= end; i++){
16077 for(var i = start; i >= end; i--){
16085 * Finds the index of the passed node
16086 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16087 * @return {Number} The index of the node or -1
16089 indexOf : function(node){
16090 node = this.getNode(node);
16091 if(typeof node.nodeIndex == "number"){
16092 return node.nodeIndex;
16094 var ns = this.nodes;
16095 for(var i = 0, len = ns.length; i < len; i++){
16106 * based on jquery fullcalendar
16110 Roo.bootstrap = Roo.bootstrap || {};
16112 * @class Roo.bootstrap.Calendar
16113 * @extends Roo.bootstrap.Component
16114 * Bootstrap Calendar class
16115 * @cfg {Boolean} loadMask (true|false) default false
16116 * @cfg {Object} header generate the user specific header of the calendar, default false
16119 * Create a new Container
16120 * @param {Object} config The config object
16125 Roo.bootstrap.Calendar = function(config){
16126 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16130 * Fires when a date is selected
16131 * @param {DatePicker} this
16132 * @param {Date} date The selected date
16136 * @event monthchange
16137 * Fires when the displayed month changes
16138 * @param {DatePicker} this
16139 * @param {Date} date The selected month
16141 'monthchange': true,
16143 * @event evententer
16144 * Fires when mouse over an event
16145 * @param {Calendar} this
16146 * @param {event} Event
16148 'evententer': true,
16150 * @event eventleave
16151 * Fires when the mouse leaves an
16152 * @param {Calendar} this
16155 'eventleave': true,
16157 * @event eventclick
16158 * Fires when the mouse click an
16159 * @param {Calendar} this
16168 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16171 * @cfg {Number} startDay
16172 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16180 getAutoCreate : function(){
16183 var fc_button = function(name, corner, style, content ) {
16184 return Roo.apply({},{
16186 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16188 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16191 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16202 style : 'width:100%',
16209 cls : 'fc-header-left',
16211 fc_button('prev', 'left', 'arrow', '‹' ),
16212 fc_button('next', 'right', 'arrow', '›' ),
16213 { tag: 'span', cls: 'fc-header-space' },
16214 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16222 cls : 'fc-header-center',
16226 cls: 'fc-header-title',
16229 html : 'month / year'
16237 cls : 'fc-header-right',
16239 /* fc_button('month', 'left', '', 'month' ),
16240 fc_button('week', '', '', 'week' ),
16241 fc_button('day', 'right', '', 'day' )
16253 header = this.header;
16256 var cal_heads = function() {
16258 // fixme - handle this.
16260 for (var i =0; i < Date.dayNames.length; i++) {
16261 var d = Date.dayNames[i];
16264 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16265 html : d.substring(0,3)
16269 ret[0].cls += ' fc-first';
16270 ret[6].cls += ' fc-last';
16273 var cal_cell = function(n) {
16276 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16281 cls: 'fc-day-number',
16285 cls: 'fc-day-content',
16289 style: 'position: relative;' // height: 17px;
16301 var cal_rows = function() {
16304 for (var r = 0; r < 6; r++) {
16311 for (var i =0; i < Date.dayNames.length; i++) {
16312 var d = Date.dayNames[i];
16313 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16316 row.cn[0].cls+=' fc-first';
16317 row.cn[0].cn[0].style = 'min-height:90px';
16318 row.cn[6].cls+=' fc-last';
16322 ret[0].cls += ' fc-first';
16323 ret[4].cls += ' fc-prev-last';
16324 ret[5].cls += ' fc-last';
16331 cls: 'fc-border-separate',
16332 style : 'width:100%',
16340 cls : 'fc-first fc-last',
16358 cls : 'fc-content',
16359 style : "position: relative;",
16362 cls : 'fc-view fc-view-month fc-grid',
16363 style : 'position: relative',
16364 unselectable : 'on',
16367 cls : 'fc-event-container',
16368 style : 'position:absolute;z-index:8;top:0;left:0;'
16386 initEvents : function()
16389 throw "can not find store for calendar";
16395 style: "text-align:center",
16399 style: "background-color:white;width:50%;margin:250 auto",
16403 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16414 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16416 var size = this.el.select('.fc-content', true).first().getSize();
16417 this.maskEl.setSize(size.width, size.height);
16418 this.maskEl.enableDisplayMode("block");
16419 if(!this.loadMask){
16420 this.maskEl.hide();
16423 this.store = Roo.factory(this.store, Roo.data);
16424 this.store.on('load', this.onLoad, this);
16425 this.store.on('beforeload', this.onBeforeLoad, this);
16429 this.cells = this.el.select('.fc-day',true);
16430 //Roo.log(this.cells);
16431 this.textNodes = this.el.query('.fc-day-number');
16432 this.cells.addClassOnOver('fc-state-hover');
16434 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16435 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16436 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16437 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16439 this.on('monthchange', this.onMonthChange, this);
16441 this.update(new Date().clearTime());
16444 resize : function() {
16445 var sz = this.el.getSize();
16447 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16448 this.el.select('.fc-day-content div',true).setHeight(34);
16453 showPrevMonth : function(e){
16454 this.update(this.activeDate.add("mo", -1));
16456 showToday : function(e){
16457 this.update(new Date().clearTime());
16460 showNextMonth : function(e){
16461 this.update(this.activeDate.add("mo", 1));
16465 showPrevYear : function(){
16466 this.update(this.activeDate.add("y", -1));
16470 showNextYear : function(){
16471 this.update(this.activeDate.add("y", 1));
16476 update : function(date)
16478 var vd = this.activeDate;
16479 this.activeDate = date;
16480 // if(vd && this.el){
16481 // var t = date.getTime();
16482 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16483 // Roo.log('using add remove');
16485 // this.fireEvent('monthchange', this, date);
16487 // this.cells.removeClass("fc-state-highlight");
16488 // this.cells.each(function(c){
16489 // if(c.dateValue == t){
16490 // c.addClass("fc-state-highlight");
16491 // setTimeout(function(){
16492 // try{c.dom.firstChild.focus();}catch(e){}
16502 var days = date.getDaysInMonth();
16504 var firstOfMonth = date.getFirstDateOfMonth();
16505 var startingPos = firstOfMonth.getDay()-this.startDay;
16507 if(startingPos < this.startDay){
16511 var pm = date.add(Date.MONTH, -1);
16512 var prevStart = pm.getDaysInMonth()-startingPos;
16514 this.cells = this.el.select('.fc-day',true);
16515 this.textNodes = this.el.query('.fc-day-number');
16516 this.cells.addClassOnOver('fc-state-hover');
16518 var cells = this.cells.elements;
16519 var textEls = this.textNodes;
16521 Roo.each(cells, function(cell){
16522 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16525 days += startingPos;
16527 // convert everything to numbers so it's fast
16528 var day = 86400000;
16529 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16532 //Roo.log(prevStart);
16534 var today = new Date().clearTime().getTime();
16535 var sel = date.clearTime().getTime();
16536 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16537 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16538 var ddMatch = this.disabledDatesRE;
16539 var ddText = this.disabledDatesText;
16540 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16541 var ddaysText = this.disabledDaysText;
16542 var format = this.format;
16544 var setCellClass = function(cal, cell){
16548 //Roo.log('set Cell Class');
16550 var t = d.getTime();
16554 cell.dateValue = t;
16556 cell.className += " fc-today";
16557 cell.className += " fc-state-highlight";
16558 cell.title = cal.todayText;
16561 // disable highlight in other month..
16562 //cell.className += " fc-state-highlight";
16567 cell.className = " fc-state-disabled";
16568 cell.title = cal.minText;
16572 cell.className = " fc-state-disabled";
16573 cell.title = cal.maxText;
16577 if(ddays.indexOf(d.getDay()) != -1){
16578 cell.title = ddaysText;
16579 cell.className = " fc-state-disabled";
16582 if(ddMatch && format){
16583 var fvalue = d.dateFormat(format);
16584 if(ddMatch.test(fvalue)){
16585 cell.title = ddText.replace("%0", fvalue);
16586 cell.className = " fc-state-disabled";
16590 if (!cell.initialClassName) {
16591 cell.initialClassName = cell.dom.className;
16594 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16599 for(; i < startingPos; i++) {
16600 textEls[i].innerHTML = (++prevStart);
16601 d.setDate(d.getDate()+1);
16603 cells[i].className = "fc-past fc-other-month";
16604 setCellClass(this, cells[i]);
16609 for(; i < days; i++){
16610 intDay = i - startingPos + 1;
16611 textEls[i].innerHTML = (intDay);
16612 d.setDate(d.getDate()+1);
16614 cells[i].className = ''; // "x-date-active";
16615 setCellClass(this, cells[i]);
16619 for(; i < 42; i++) {
16620 textEls[i].innerHTML = (++extraDays);
16621 d.setDate(d.getDate()+1);
16623 cells[i].className = "fc-future fc-other-month";
16624 setCellClass(this, cells[i]);
16627 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16629 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16631 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16632 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16634 if(totalRows != 6){
16635 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16636 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16639 this.fireEvent('monthchange', this, date);
16643 if(!this.internalRender){
16644 var main = this.el.dom.firstChild;
16645 var w = main.offsetWidth;
16646 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16647 Roo.fly(main).setWidth(w);
16648 this.internalRender = true;
16649 // opera does not respect the auto grow header center column
16650 // then, after it gets a width opera refuses to recalculate
16651 // without a second pass
16652 if(Roo.isOpera && !this.secondPass){
16653 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16654 this.secondPass = true;
16655 this.update.defer(10, this, [date]);
16662 findCell : function(dt) {
16663 dt = dt.clearTime().getTime();
16665 this.cells.each(function(c){
16666 //Roo.log("check " +c.dateValue + '?=' + dt);
16667 if(c.dateValue == dt){
16677 findCells : function(ev) {
16678 var s = ev.start.clone().clearTime().getTime();
16680 var e= ev.end.clone().clearTime().getTime();
16683 this.cells.each(function(c){
16684 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16686 if(c.dateValue > e){
16689 if(c.dateValue < s){
16698 // findBestRow: function(cells)
16702 // for (var i =0 ; i < cells.length;i++) {
16703 // ret = Math.max(cells[i].rows || 0,ret);
16710 addItem : function(ev)
16712 // look for vertical location slot in
16713 var cells = this.findCells(ev);
16715 // ev.row = this.findBestRow(cells);
16717 // work out the location.
16721 for(var i =0; i < cells.length; i++) {
16723 cells[i].row = cells[0].row;
16726 cells[i].row = cells[i].row + 1;
16736 if (crow.start.getY() == cells[i].getY()) {
16738 crow.end = cells[i];
16755 cells[0].events.push(ev);
16757 this.calevents.push(ev);
16760 clearEvents: function() {
16762 if(!this.calevents){
16766 Roo.each(this.cells.elements, function(c){
16772 Roo.each(this.calevents, function(e) {
16773 Roo.each(e.els, function(el) {
16774 el.un('mouseenter' ,this.onEventEnter, this);
16775 el.un('mouseleave' ,this.onEventLeave, this);
16780 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16786 renderEvents: function()
16790 this.cells.each(function(c) {
16799 if(c.row != c.events.length){
16800 r = 4 - (4 - (c.row - c.events.length));
16803 c.events = ev.slice(0, r);
16804 c.more = ev.slice(r);
16806 if(c.more.length && c.more.length == 1){
16807 c.events.push(c.more.pop());
16810 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16814 this.cells.each(function(c) {
16816 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16819 for (var e = 0; e < c.events.length; e++){
16820 var ev = c.events[e];
16821 var rows = ev.rows;
16823 for(var i = 0; i < rows.length; i++) {
16825 // how many rows should it span..
16828 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16829 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16831 unselectable : "on",
16834 cls: 'fc-event-inner',
16838 // cls: 'fc-event-time',
16839 // html : cells.length > 1 ? '' : ev.time
16843 cls: 'fc-event-title',
16844 html : String.format('{0}', ev.title)
16851 cls: 'ui-resizable-handle ui-resizable-e',
16852 html : '  '
16859 cfg.cls += ' fc-event-start';
16861 if ((i+1) == rows.length) {
16862 cfg.cls += ' fc-event-end';
16865 var ctr = _this.el.select('.fc-event-container',true).first();
16866 var cg = ctr.createChild(cfg);
16868 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16869 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16871 var r = (c.more.length) ? 1 : 0;
16872 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16873 cg.setWidth(ebox.right - sbox.x -2);
16875 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16876 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16877 cg.on('click', _this.onEventClick, _this, ev);
16888 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16889 style : 'position: absolute',
16890 unselectable : "on",
16893 cls: 'fc-event-inner',
16897 cls: 'fc-event-title',
16905 cls: 'ui-resizable-handle ui-resizable-e',
16906 html : '  '
16912 var ctr = _this.el.select('.fc-event-container',true).first();
16913 var cg = ctr.createChild(cfg);
16915 var sbox = c.select('.fc-day-content',true).first().getBox();
16916 var ebox = c.select('.fc-day-content',true).first().getBox();
16918 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16919 cg.setWidth(ebox.right - sbox.x -2);
16921 cg.on('click', _this.onMoreEventClick, _this, c.more);
16931 onEventEnter: function (e, el,event,d) {
16932 this.fireEvent('evententer', this, el, event);
16935 onEventLeave: function (e, el,event,d) {
16936 this.fireEvent('eventleave', this, el, event);
16939 onEventClick: function (e, el,event,d) {
16940 this.fireEvent('eventclick', this, el, event);
16943 onMonthChange: function () {
16947 onMoreEventClick: function(e, el, more)
16951 this.calpopover.placement = 'right';
16952 this.calpopover.setTitle('More');
16954 this.calpopover.setContent('');
16956 var ctr = this.calpopover.el.select('.popover-content', true).first();
16958 Roo.each(more, function(m){
16960 cls : 'fc-event-hori fc-event-draggable',
16963 var cg = ctr.createChild(cfg);
16965 cg.on('click', _this.onEventClick, _this, m);
16968 this.calpopover.show(el);
16973 onLoad: function ()
16975 this.calevents = [];
16978 if(this.store.getCount() > 0){
16979 this.store.data.each(function(d){
16982 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16983 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16984 time : d.data.start_time,
16985 title : d.data.title,
16986 description : d.data.description,
16987 venue : d.data.venue
16992 this.renderEvents();
16994 if(this.calevents.length && this.loadMask){
16995 this.maskEl.hide();
16999 onBeforeLoad: function()
17001 this.clearEvents();
17003 this.maskEl.show();
17017 * @class Roo.bootstrap.Popover
17018 * @extends Roo.bootstrap.Component
17019 * Bootstrap Popover class
17020 * @cfg {String} html contents of the popover (or false to use children..)
17021 * @cfg {String} title of popover (or false to hide)
17022 * @cfg {String} placement how it is placed
17023 * @cfg {String} trigger click || hover (or false to trigger manually)
17024 * @cfg {String} over what (parent or false to trigger manually.)
17025 * @cfg {Number} delay - delay before showing
17028 * Create a new Popover
17029 * @param {Object} config The config object
17032 Roo.bootstrap.Popover = function(config){
17033 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17039 * After the popover show
17041 * @param {Roo.bootstrap.Popover} this
17046 * After the popover hide
17048 * @param {Roo.bootstrap.Popover} this
17054 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17056 title: 'Fill in a title',
17059 placement : 'right',
17060 trigger : 'hover', // hover
17066 can_build_overlaid : false,
17068 getChildContainer : function()
17070 return this.el.select('.popover-content',true).first();
17073 getAutoCreate : function(){
17076 cls : 'popover roo-dynamic',
17077 style: 'display:block',
17083 cls : 'popover-inner',
17087 cls: 'popover-title',
17091 cls : 'popover-content',
17102 setTitle: function(str)
17105 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17107 setContent: function(str)
17110 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17112 // as it get's added to the bottom of the page.
17113 onRender : function(ct, position)
17115 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17117 var cfg = Roo.apply({}, this.getAutoCreate());
17121 cfg.cls += ' ' + this.cls;
17124 cfg.style = this.style;
17126 //Roo.log("adding to ");
17127 this.el = Roo.get(document.body).createChild(cfg, position);
17128 // Roo.log(this.el);
17133 initEvents : function()
17135 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17136 this.el.enableDisplayMode('block');
17138 if (this.over === false) {
17141 if (this.triggers === false) {
17144 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17145 var triggers = this.trigger ? this.trigger.split(' ') : [];
17146 Roo.each(triggers, function(trigger) {
17148 if (trigger == 'click') {
17149 on_el.on('click', this.toggle, this);
17150 } else if (trigger != 'manual') {
17151 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17152 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17154 on_el.on(eventIn ,this.enter, this);
17155 on_el.on(eventOut, this.leave, this);
17166 toggle : function () {
17167 this.hoverState == 'in' ? this.leave() : this.enter();
17170 enter : function () {
17172 clearTimeout(this.timeout);
17174 this.hoverState = 'in';
17176 if (!this.delay || !this.delay.show) {
17181 this.timeout = setTimeout(function () {
17182 if (_t.hoverState == 'in') {
17185 }, this.delay.show)
17188 leave : function() {
17189 clearTimeout(this.timeout);
17191 this.hoverState = 'out';
17193 if (!this.delay || !this.delay.hide) {
17198 this.timeout = setTimeout(function () {
17199 if (_t.hoverState == 'out') {
17202 }, this.delay.hide)
17205 show : function (on_el)
17208 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17212 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17213 if (this.html !== false) {
17214 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17216 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17217 if (!this.title.length) {
17218 this.el.select('.popover-title',true).hide();
17221 var placement = typeof this.placement == 'function' ?
17222 this.placement.call(this, this.el, on_el) :
17225 var autoToken = /\s?auto?\s?/i;
17226 var autoPlace = autoToken.test(placement);
17228 placement = placement.replace(autoToken, '') || 'top';
17232 //this.el.setXY([0,0]);
17234 this.el.dom.style.display='block';
17235 this.el.addClass(placement);
17237 //this.el.appendTo(on_el);
17239 var p = this.getPosition();
17240 var box = this.el.getBox();
17245 var align = Roo.bootstrap.Popover.alignment[placement];
17246 this.el.alignTo(on_el, align[0],align[1]);
17247 //var arrow = this.el.select('.arrow',true).first();
17248 //arrow.set(align[2],
17250 this.el.addClass('in');
17253 if (this.el.hasClass('fade')) {
17257 this.hoverState = 'in';
17259 this.fireEvent('show', this);
17264 this.el.setXY([0,0]);
17265 this.el.removeClass('in');
17267 this.hoverState = null;
17269 this.fireEvent('hide', this);
17274 Roo.bootstrap.Popover.alignment = {
17275 'left' : ['r-l', [-10,0], 'right'],
17276 'right' : ['l-r', [10,0], 'left'],
17277 'bottom' : ['t-b', [0,10], 'top'],
17278 'top' : [ 'b-t', [0,-10], 'bottom']
17289 * @class Roo.bootstrap.Progress
17290 * @extends Roo.bootstrap.Component
17291 * Bootstrap Progress class
17292 * @cfg {Boolean} striped striped of the progress bar
17293 * @cfg {Boolean} active animated of the progress bar
17297 * Create a new Progress
17298 * @param {Object} config The config object
17301 Roo.bootstrap.Progress = function(config){
17302 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17305 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17310 getAutoCreate : function(){
17318 cfg.cls += ' progress-striped';
17322 cfg.cls += ' active';
17341 * @class Roo.bootstrap.ProgressBar
17342 * @extends Roo.bootstrap.Component
17343 * Bootstrap ProgressBar class
17344 * @cfg {Number} aria_valuenow aria-value now
17345 * @cfg {Number} aria_valuemin aria-value min
17346 * @cfg {Number} aria_valuemax aria-value max
17347 * @cfg {String} label label for the progress bar
17348 * @cfg {String} panel (success | info | warning | danger )
17349 * @cfg {String} role role of the progress bar
17350 * @cfg {String} sr_only text
17354 * Create a new ProgressBar
17355 * @param {Object} config The config object
17358 Roo.bootstrap.ProgressBar = function(config){
17359 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17362 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17366 aria_valuemax : 100,
17372 getAutoCreate : function()
17377 cls: 'progress-bar',
17378 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17390 cfg.role = this.role;
17393 if(this.aria_valuenow){
17394 cfg['aria-valuenow'] = this.aria_valuenow;
17397 if(this.aria_valuemin){
17398 cfg['aria-valuemin'] = this.aria_valuemin;
17401 if(this.aria_valuemax){
17402 cfg['aria-valuemax'] = this.aria_valuemax;
17405 if(this.label && !this.sr_only){
17406 cfg.html = this.label;
17410 cfg.cls += ' progress-bar-' + this.panel;
17416 update : function(aria_valuenow)
17418 this.aria_valuenow = aria_valuenow;
17420 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17435 * @class Roo.bootstrap.TabGroup
17436 * @extends Roo.bootstrap.Column
17437 * Bootstrap Column class
17438 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17439 * @cfg {Boolean} carousel true to make the group behave like a carousel
17440 * @cfg {Boolean} bullets show bullets for the panels
17441 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17442 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17443 * @cfg {Boolean} showarrow (true|false) show arrow default true
17446 * Create a new TabGroup
17447 * @param {Object} config The config object
17450 Roo.bootstrap.TabGroup = function(config){
17451 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17453 this.navId = Roo.id();
17456 Roo.bootstrap.TabGroup.register(this);
17460 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17463 transition : false,
17468 slideOnTouch : false,
17471 getAutoCreate : function()
17473 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17475 cfg.cls += ' tab-content';
17477 if (this.carousel) {
17478 cfg.cls += ' carousel slide';
17481 cls : 'carousel-inner',
17485 if(this.bullets && !Roo.isTouch){
17488 cls : 'carousel-bullets',
17492 if(this.bullets_cls){
17493 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17500 cfg.cn[0].cn.push(bullets);
17503 if(this.showarrow){
17504 cfg.cn[0].cn.push({
17506 class : 'carousel-arrow',
17510 class : 'carousel-prev',
17514 class : 'fa fa-chevron-left'
17520 class : 'carousel-next',
17524 class : 'fa fa-chevron-right'
17537 initEvents: function()
17539 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17540 // this.el.on("touchstart", this.onTouchStart, this);
17543 if(this.autoslide){
17546 this.slideFn = window.setInterval(function() {
17547 _this.showPanelNext();
17551 if(this.showarrow){
17552 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17553 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17559 // onTouchStart : function(e, el, o)
17561 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17565 // this.showPanelNext();
17569 getChildContainer : function()
17571 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17575 * register a Navigation item
17576 * @param {Roo.bootstrap.NavItem} the navitem to add
17578 register : function(item)
17580 this.tabs.push( item);
17581 item.navId = this.navId; // not really needed..
17586 getActivePanel : function()
17589 Roo.each(this.tabs, function(t) {
17599 getPanelByName : function(n)
17602 Roo.each(this.tabs, function(t) {
17603 if (t.tabId == n) {
17611 indexOfPanel : function(p)
17614 Roo.each(this.tabs, function(t,i) {
17615 if (t.tabId == p.tabId) {
17624 * show a specific panel
17625 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17626 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17628 showPanel : function (pan)
17630 if(this.transition || typeof(pan) == 'undefined'){
17631 Roo.log("waiting for the transitionend");
17635 if (typeof(pan) == 'number') {
17636 pan = this.tabs[pan];
17639 if (typeof(pan) == 'string') {
17640 pan = this.getPanelByName(pan);
17643 var cur = this.getActivePanel();
17646 Roo.log('pan or acitve pan is undefined');
17650 if (pan.tabId == this.getActivePanel().tabId) {
17654 if (false === cur.fireEvent('beforedeactivate')) {
17658 if(this.bullets > 0 && !Roo.isTouch){
17659 this.setActiveBullet(this.indexOfPanel(pan));
17662 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17664 this.transition = true;
17665 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17666 var lr = dir == 'next' ? 'left' : 'right';
17667 pan.el.addClass(dir); // or prev
17668 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17669 cur.el.addClass(lr); // or right
17670 pan.el.addClass(lr);
17673 cur.el.on('transitionend', function() {
17674 Roo.log("trans end?");
17676 pan.el.removeClass([lr,dir]);
17677 pan.setActive(true);
17679 cur.el.removeClass([lr]);
17680 cur.setActive(false);
17682 _this.transition = false;
17684 }, this, { single: true } );
17689 cur.setActive(false);
17690 pan.setActive(true);
17695 showPanelNext : function()
17697 var i = this.indexOfPanel(this.getActivePanel());
17699 if (i >= this.tabs.length - 1 && !this.autoslide) {
17703 if (i >= this.tabs.length - 1 && this.autoslide) {
17707 this.showPanel(this.tabs[i+1]);
17710 showPanelPrev : function()
17712 var i = this.indexOfPanel(this.getActivePanel());
17714 if (i < 1 && !this.autoslide) {
17718 if (i < 1 && this.autoslide) {
17719 i = this.tabs.length;
17722 this.showPanel(this.tabs[i-1]);
17726 addBullet: function()
17728 if(!this.bullets || Roo.isTouch){
17731 var ctr = this.el.select('.carousel-bullets',true).first();
17732 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17733 var bullet = ctr.createChild({
17734 cls : 'bullet bullet-' + i
17735 },ctr.dom.lastChild);
17740 bullet.on('click', (function(e, el, o, ii, t){
17742 e.preventDefault();
17744 this.showPanel(ii);
17746 if(this.autoslide && this.slideFn){
17747 clearInterval(this.slideFn);
17748 this.slideFn = window.setInterval(function() {
17749 _this.showPanelNext();
17753 }).createDelegate(this, [i, bullet], true));
17758 setActiveBullet : function(i)
17764 Roo.each(this.el.select('.bullet', true).elements, function(el){
17765 el.removeClass('selected');
17768 var bullet = this.el.select('.bullet-' + i, true).first();
17774 bullet.addClass('selected');
17785 Roo.apply(Roo.bootstrap.TabGroup, {
17789 * register a Navigation Group
17790 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17792 register : function(navgrp)
17794 this.groups[navgrp.navId] = navgrp;
17798 * fetch a Navigation Group based on the navigation ID
17799 * if one does not exist , it will get created.
17800 * @param {string} the navgroup to add
17801 * @returns {Roo.bootstrap.NavGroup} the navgroup
17803 get: function(navId) {
17804 if (typeof(this.groups[navId]) == 'undefined') {
17805 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17807 return this.groups[navId] ;
17822 * @class Roo.bootstrap.TabPanel
17823 * @extends Roo.bootstrap.Component
17824 * Bootstrap TabPanel class
17825 * @cfg {Boolean} active panel active
17826 * @cfg {String} html panel content
17827 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17828 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17829 * @cfg {String} href click to link..
17833 * Create a new TabPanel
17834 * @param {Object} config The config object
17837 Roo.bootstrap.TabPanel = function(config){
17838 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17842 * Fires when the active status changes
17843 * @param {Roo.bootstrap.TabPanel} this
17844 * @param {Boolean} state the new state
17849 * @event beforedeactivate
17850 * Fires before a tab is de-activated - can be used to do validation on a form.
17851 * @param {Roo.bootstrap.TabPanel} this
17852 * @return {Boolean} false if there is an error
17855 'beforedeactivate': true
17858 this.tabId = this.tabId || Roo.id();
17862 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17870 getAutoCreate : function(){
17873 // item is needed for carousel - not sure if it has any effect otherwise
17874 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17875 html: this.html || ''
17879 cfg.cls += ' active';
17883 cfg.tabId = this.tabId;
17890 initEvents: function()
17892 var p = this.parent();
17894 this.navId = this.navId || p.navId;
17896 if (typeof(this.navId) != 'undefined') {
17897 // not really needed.. but just in case.. parent should be a NavGroup.
17898 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17902 var i = tg.tabs.length - 1;
17904 if(this.active && tg.bullets > 0 && i < tg.bullets){
17905 tg.setActiveBullet(i);
17909 this.el.on('click', this.onClick, this);
17912 this.el.on("touchstart", this.onTouchStart, this);
17913 this.el.on("touchmove", this.onTouchMove, this);
17914 this.el.on("touchend", this.onTouchEnd, this);
17919 onRender : function(ct, position)
17921 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17924 setActive : function(state)
17926 Roo.log("panel - set active " + this.tabId + "=" + state);
17928 this.active = state;
17930 this.el.removeClass('active');
17932 } else if (!this.el.hasClass('active')) {
17933 this.el.addClass('active');
17936 this.fireEvent('changed', this, state);
17939 onClick : function(e)
17941 e.preventDefault();
17943 if(!this.href.length){
17947 window.location.href = this.href;
17956 onTouchStart : function(e)
17958 this.swiping = false;
17960 this.startX = e.browserEvent.touches[0].clientX;
17961 this.startY = e.browserEvent.touches[0].clientY;
17964 onTouchMove : function(e)
17966 this.swiping = true;
17968 this.endX = e.browserEvent.touches[0].clientX;
17969 this.endY = e.browserEvent.touches[0].clientY;
17972 onTouchEnd : function(e)
17979 var tabGroup = this.parent();
17981 if(this.endX > this.startX){ // swiping right
17982 tabGroup.showPanelPrev();
17986 if(this.startX > this.endX){ // swiping left
17987 tabGroup.showPanelNext();
18006 * @class Roo.bootstrap.DateField
18007 * @extends Roo.bootstrap.Input
18008 * Bootstrap DateField class
18009 * @cfg {Number} weekStart default 0
18010 * @cfg {String} viewMode default empty, (months|years)
18011 * @cfg {String} minViewMode default empty, (months|years)
18012 * @cfg {Number} startDate default -Infinity
18013 * @cfg {Number} endDate default Infinity
18014 * @cfg {Boolean} todayHighlight default false
18015 * @cfg {Boolean} todayBtn default false
18016 * @cfg {Boolean} calendarWeeks default false
18017 * @cfg {Object} daysOfWeekDisabled default empty
18018 * @cfg {Boolean} singleMode default false (true | false)
18020 * @cfg {Boolean} keyboardNavigation default true
18021 * @cfg {String} language default en
18024 * Create a new DateField
18025 * @param {Object} config The config object
18028 Roo.bootstrap.DateField = function(config){
18029 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18033 * Fires when this field show.
18034 * @param {Roo.bootstrap.DateField} this
18035 * @param {Mixed} date The date value
18040 * Fires when this field hide.
18041 * @param {Roo.bootstrap.DateField} this
18042 * @param {Mixed} date The date value
18047 * Fires when select a date.
18048 * @param {Roo.bootstrap.DateField} this
18049 * @param {Mixed} date The date value
18053 * @event beforeselect
18054 * Fires when before select a date.
18055 * @param {Roo.bootstrap.DateField} this
18056 * @param {Mixed} date The date value
18058 beforeselect : true
18062 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18065 * @cfg {String} format
18066 * The default date format string which can be overriden for localization support. The format must be
18067 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18071 * @cfg {String} altFormats
18072 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18073 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18075 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18083 todayHighlight : false,
18089 keyboardNavigation: true,
18091 calendarWeeks: false,
18093 startDate: -Infinity,
18097 daysOfWeekDisabled: [],
18101 singleMode : false,
18103 UTCDate: function()
18105 return new Date(Date.UTC.apply(Date, arguments));
18108 UTCToday: function()
18110 var today = new Date();
18111 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18114 getDate: function() {
18115 var d = this.getUTCDate();
18116 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18119 getUTCDate: function() {
18123 setDate: function(d) {
18124 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18127 setUTCDate: function(d) {
18129 this.setValue(this.formatDate(this.date));
18132 onRender: function(ct, position)
18135 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18137 this.language = this.language || 'en';
18138 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18139 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18141 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18142 this.format = this.format || 'm/d/y';
18143 this.isInline = false;
18144 this.isInput = true;
18145 this.component = this.el.select('.add-on', true).first() || false;
18146 this.component = (this.component && this.component.length === 0) ? false : this.component;
18147 this.hasInput = this.component && this.inputEl().length;
18149 if (typeof(this.minViewMode === 'string')) {
18150 switch (this.minViewMode) {
18152 this.minViewMode = 1;
18155 this.minViewMode = 2;
18158 this.minViewMode = 0;
18163 if (typeof(this.viewMode === 'string')) {
18164 switch (this.viewMode) {
18177 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18179 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18181 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18183 this.picker().on('mousedown', this.onMousedown, this);
18184 this.picker().on('click', this.onClick, this);
18186 this.picker().addClass('datepicker-dropdown');
18188 this.startViewMode = this.viewMode;
18190 if(this.singleMode){
18191 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18192 v.setVisibilityMode(Roo.Element.DISPLAY);
18196 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18197 v.setStyle('width', '189px');
18201 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18202 if(!this.calendarWeeks){
18207 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18208 v.attr('colspan', function(i, val){
18209 return parseInt(val) + 1;
18214 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18216 this.setStartDate(this.startDate);
18217 this.setEndDate(this.endDate);
18219 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18226 if(this.isInline) {
18231 picker : function()
18233 return this.pickerEl;
18234 // return this.el.select('.datepicker', true).first();
18237 fillDow: function()
18239 var dowCnt = this.weekStart;
18248 if(this.calendarWeeks){
18256 while (dowCnt < this.weekStart + 7) {
18260 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18264 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18267 fillMonths: function()
18270 var months = this.picker().select('>.datepicker-months td', true).first();
18272 months.dom.innerHTML = '';
18278 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18281 months.createChild(month);
18288 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;
18290 if (this.date < this.startDate) {
18291 this.viewDate = new Date(this.startDate);
18292 } else if (this.date > this.endDate) {
18293 this.viewDate = new Date(this.endDate);
18295 this.viewDate = new Date(this.date);
18303 var d = new Date(this.viewDate),
18304 year = d.getUTCFullYear(),
18305 month = d.getUTCMonth(),
18306 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18307 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18308 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18309 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18310 currentDate = this.date && this.date.valueOf(),
18311 today = this.UTCToday();
18313 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18315 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18317 // this.picker.select('>tfoot th.today').
18318 // .text(dates[this.language].today)
18319 // .toggle(this.todayBtn !== false);
18321 this.updateNavArrows();
18324 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18326 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18328 prevMonth.setUTCDate(day);
18330 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18332 var nextMonth = new Date(prevMonth);
18334 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18336 nextMonth = nextMonth.valueOf();
18338 var fillMonths = false;
18340 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18342 while(prevMonth.valueOf() < nextMonth) {
18345 if (prevMonth.getUTCDay() === this.weekStart) {
18347 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18355 if(this.calendarWeeks){
18356 // ISO 8601: First week contains first thursday.
18357 // ISO also states week starts on Monday, but we can be more abstract here.
18359 // Start of current week: based on weekstart/current date
18360 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18361 // Thursday of this week
18362 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18363 // First Thursday of year, year from thursday
18364 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18365 // Calendar week: ms between thursdays, div ms per day, div 7 days
18366 calWeek = (th - yth) / 864e5 / 7 + 1;
18368 fillMonths.cn.push({
18376 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18378 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18381 if (this.todayHighlight &&
18382 prevMonth.getUTCFullYear() == today.getFullYear() &&
18383 prevMonth.getUTCMonth() == today.getMonth() &&
18384 prevMonth.getUTCDate() == today.getDate()) {
18385 clsName += ' today';
18388 if (currentDate && prevMonth.valueOf() === currentDate) {
18389 clsName += ' active';
18392 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18393 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18394 clsName += ' disabled';
18397 fillMonths.cn.push({
18399 cls: 'day ' + clsName,
18400 html: prevMonth.getDate()
18403 prevMonth.setDate(prevMonth.getDate()+1);
18406 var currentYear = this.date && this.date.getUTCFullYear();
18407 var currentMonth = this.date && this.date.getUTCMonth();
18409 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18411 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18412 v.removeClass('active');
18414 if(currentYear === year && k === currentMonth){
18415 v.addClass('active');
18418 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18419 v.addClass('disabled');
18425 year = parseInt(year/10, 10) * 10;
18427 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18429 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18432 for (var i = -1; i < 11; i++) {
18433 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18435 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18443 showMode: function(dir)
18446 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18449 Roo.each(this.picker().select('>div',true).elements, function(v){
18450 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18453 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18458 if(this.isInline) {
18462 this.picker().removeClass(['bottom', 'top']);
18464 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18466 * place to the top of element!
18470 this.picker().addClass('top');
18471 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18476 this.picker().addClass('bottom');
18478 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18481 parseDate : function(value)
18483 if(!value || value instanceof Date){
18486 var v = Date.parseDate(value, this.format);
18487 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18488 v = Date.parseDate(value, 'Y-m-d');
18490 if(!v && this.altFormats){
18491 if(!this.altFormatsArray){
18492 this.altFormatsArray = this.altFormats.split("|");
18494 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18495 v = Date.parseDate(value, this.altFormatsArray[i]);
18501 formatDate : function(date, fmt)
18503 return (!date || !(date instanceof Date)) ?
18504 date : date.dateFormat(fmt || this.format);
18507 onFocus : function()
18509 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18513 onBlur : function()
18515 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18517 var d = this.inputEl().getValue();
18526 this.picker().show();
18530 this.fireEvent('show', this, this.date);
18535 if(this.isInline) {
18538 this.picker().hide();
18539 this.viewMode = this.startViewMode;
18542 this.fireEvent('hide', this, this.date);
18546 onMousedown: function(e)
18548 e.stopPropagation();
18549 e.preventDefault();
18554 Roo.bootstrap.DateField.superclass.keyup.call(this);
18558 setValue: function(v)
18560 if(this.fireEvent('beforeselect', this, v) !== false){
18561 var d = new Date(this.parseDate(v) ).clearTime();
18563 if(isNaN(d.getTime())){
18564 this.date = this.viewDate = '';
18565 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18569 v = this.formatDate(d);
18571 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18573 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18577 this.fireEvent('select', this, this.date);
18581 getValue: function()
18583 return this.formatDate(this.date);
18586 fireKey: function(e)
18588 if (!this.picker().isVisible()){
18589 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18595 var dateChanged = false,
18597 newDate, newViewDate;
18602 e.preventDefault();
18606 if (!this.keyboardNavigation) {
18609 dir = e.keyCode == 37 ? -1 : 1;
18612 newDate = this.moveYear(this.date, dir);
18613 newViewDate = this.moveYear(this.viewDate, dir);
18614 } else if (e.shiftKey){
18615 newDate = this.moveMonth(this.date, dir);
18616 newViewDate = this.moveMonth(this.viewDate, dir);
18618 newDate = new Date(this.date);
18619 newDate.setUTCDate(this.date.getUTCDate() + dir);
18620 newViewDate = new Date(this.viewDate);
18621 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18623 if (this.dateWithinRange(newDate)){
18624 this.date = newDate;
18625 this.viewDate = newViewDate;
18626 this.setValue(this.formatDate(this.date));
18628 e.preventDefault();
18629 dateChanged = true;
18634 if (!this.keyboardNavigation) {
18637 dir = e.keyCode == 38 ? -1 : 1;
18639 newDate = this.moveYear(this.date, dir);
18640 newViewDate = this.moveYear(this.viewDate, dir);
18641 } else if (e.shiftKey){
18642 newDate = this.moveMonth(this.date, dir);
18643 newViewDate = this.moveMonth(this.viewDate, dir);
18645 newDate = new Date(this.date);
18646 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18647 newViewDate = new Date(this.viewDate);
18648 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18650 if (this.dateWithinRange(newDate)){
18651 this.date = newDate;
18652 this.viewDate = newViewDate;
18653 this.setValue(this.formatDate(this.date));
18655 e.preventDefault();
18656 dateChanged = true;
18660 this.setValue(this.formatDate(this.date));
18662 e.preventDefault();
18665 this.setValue(this.formatDate(this.date));
18679 onClick: function(e)
18681 e.stopPropagation();
18682 e.preventDefault();
18684 var target = e.getTarget();
18686 if(target.nodeName.toLowerCase() === 'i'){
18687 target = Roo.get(target).dom.parentNode;
18690 var nodeName = target.nodeName;
18691 var className = target.className;
18692 var html = target.innerHTML;
18693 //Roo.log(nodeName);
18695 switch(nodeName.toLowerCase()) {
18697 switch(className) {
18703 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18704 switch(this.viewMode){
18706 this.viewDate = this.moveMonth(this.viewDate, dir);
18710 this.viewDate = this.moveYear(this.viewDate, dir);
18716 var date = new Date();
18717 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18719 this.setValue(this.formatDate(this.date));
18726 if (className.indexOf('disabled') < 0) {
18727 this.viewDate.setUTCDate(1);
18728 if (className.indexOf('month') > -1) {
18729 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18731 var year = parseInt(html, 10) || 0;
18732 this.viewDate.setUTCFullYear(year);
18736 if(this.singleMode){
18737 this.setValue(this.formatDate(this.viewDate));
18748 //Roo.log(className);
18749 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18750 var day = parseInt(html, 10) || 1;
18751 var year = this.viewDate.getUTCFullYear(),
18752 month = this.viewDate.getUTCMonth();
18754 if (className.indexOf('old') > -1) {
18761 } else if (className.indexOf('new') > -1) {
18769 //Roo.log([year,month,day]);
18770 this.date = this.UTCDate(year, month, day,0,0,0,0);
18771 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18773 //Roo.log(this.formatDate(this.date));
18774 this.setValue(this.formatDate(this.date));
18781 setStartDate: function(startDate)
18783 this.startDate = startDate || -Infinity;
18784 if (this.startDate !== -Infinity) {
18785 this.startDate = this.parseDate(this.startDate);
18788 this.updateNavArrows();
18791 setEndDate: function(endDate)
18793 this.endDate = endDate || Infinity;
18794 if (this.endDate !== Infinity) {
18795 this.endDate = this.parseDate(this.endDate);
18798 this.updateNavArrows();
18801 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18803 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18804 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18805 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18807 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18808 return parseInt(d, 10);
18811 this.updateNavArrows();
18814 updateNavArrows: function()
18816 if(this.singleMode){
18820 var d = new Date(this.viewDate),
18821 year = d.getUTCFullYear(),
18822 month = d.getUTCMonth();
18824 Roo.each(this.picker().select('.prev', true).elements, function(v){
18826 switch (this.viewMode) {
18829 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18835 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18842 Roo.each(this.picker().select('.next', true).elements, function(v){
18844 switch (this.viewMode) {
18847 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18853 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18861 moveMonth: function(date, dir)
18866 var new_date = new Date(date.valueOf()),
18867 day = new_date.getUTCDate(),
18868 month = new_date.getUTCMonth(),
18869 mag = Math.abs(dir),
18871 dir = dir > 0 ? 1 : -1;
18874 // If going back one month, make sure month is not current month
18875 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18877 return new_date.getUTCMonth() == month;
18879 // If going forward one month, make sure month is as expected
18880 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18882 return new_date.getUTCMonth() != new_month;
18884 new_month = month + dir;
18885 new_date.setUTCMonth(new_month);
18886 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18887 if (new_month < 0 || new_month > 11) {
18888 new_month = (new_month + 12) % 12;
18891 // For magnitudes >1, move one month at a time...
18892 for (var i=0; i<mag; i++) {
18893 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18894 new_date = this.moveMonth(new_date, dir);
18896 // ...then reset the day, keeping it in the new month
18897 new_month = new_date.getUTCMonth();
18898 new_date.setUTCDate(day);
18900 return new_month != new_date.getUTCMonth();
18903 // Common date-resetting loop -- if date is beyond end of month, make it
18906 new_date.setUTCDate(--day);
18907 new_date.setUTCMonth(new_month);
18912 moveYear: function(date, dir)
18914 return this.moveMonth(date, dir*12);
18917 dateWithinRange: function(date)
18919 return date >= this.startDate && date <= this.endDate;
18925 this.picker().remove();
18928 validateValue : function(value)
18930 if(value.length < 1) {
18931 if(this.allowBlank){
18937 if(value.length < this.minLength){
18940 if(value.length > this.maxLength){
18944 var vt = Roo.form.VTypes;
18945 if(!vt[this.vtype](value, this)){
18949 if(typeof this.validator == "function"){
18950 var msg = this.validator(value);
18956 if(this.regex && !this.regex.test(value)){
18960 if(typeof(this.parseDate(value)) == 'undefined'){
18964 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18968 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18978 Roo.apply(Roo.bootstrap.DateField, {
18989 html: '<i class="fa fa-arrow-left"/>'
18999 html: '<i class="fa fa-arrow-right"/>'
19041 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19042 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19043 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19044 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19045 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19058 navFnc: 'FullYear',
19063 navFnc: 'FullYear',
19068 Roo.apply(Roo.bootstrap.DateField, {
19072 cls: 'datepicker dropdown-menu roo-dynamic',
19076 cls: 'datepicker-days',
19080 cls: 'table-condensed',
19082 Roo.bootstrap.DateField.head,
19086 Roo.bootstrap.DateField.footer
19093 cls: 'datepicker-months',
19097 cls: 'table-condensed',
19099 Roo.bootstrap.DateField.head,
19100 Roo.bootstrap.DateField.content,
19101 Roo.bootstrap.DateField.footer
19108 cls: 'datepicker-years',
19112 cls: 'table-condensed',
19114 Roo.bootstrap.DateField.head,
19115 Roo.bootstrap.DateField.content,
19116 Roo.bootstrap.DateField.footer
19135 * @class Roo.bootstrap.TimeField
19136 * @extends Roo.bootstrap.Input
19137 * Bootstrap DateField class
19141 * Create a new TimeField
19142 * @param {Object} config The config object
19145 Roo.bootstrap.TimeField = function(config){
19146 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19150 * Fires when this field show.
19151 * @param {Roo.bootstrap.DateField} thisthis
19152 * @param {Mixed} date The date value
19157 * Fires when this field hide.
19158 * @param {Roo.bootstrap.DateField} this
19159 * @param {Mixed} date The date value
19164 * Fires when select a date.
19165 * @param {Roo.bootstrap.DateField} this
19166 * @param {Mixed} date The date value
19172 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19175 * @cfg {String} format
19176 * The default time format string which can be overriden for localization support. The format must be
19177 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19181 onRender: function(ct, position)
19184 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19186 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19188 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19190 this.pop = this.picker().select('>.datepicker-time',true).first();
19191 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19193 this.picker().on('mousedown', this.onMousedown, this);
19194 this.picker().on('click', this.onClick, this);
19196 this.picker().addClass('datepicker-dropdown');
19201 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19202 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19203 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19204 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19205 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19206 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19210 fireKey: function(e){
19211 if (!this.picker().isVisible()){
19212 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19218 e.preventDefault();
19226 this.onTogglePeriod();
19229 this.onIncrementMinutes();
19232 this.onDecrementMinutes();
19241 onClick: function(e) {
19242 e.stopPropagation();
19243 e.preventDefault();
19246 picker : function()
19248 return this.el.select('.datepicker', true).first();
19251 fillTime: function()
19253 var time = this.pop.select('tbody', true).first();
19255 time.dom.innerHTML = '';
19270 cls: 'hours-up glyphicon glyphicon-chevron-up'
19290 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19311 cls: 'timepicker-hour',
19326 cls: 'timepicker-minute',
19341 cls: 'btn btn-primary period',
19363 cls: 'hours-down glyphicon glyphicon-chevron-down'
19383 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19401 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19408 var hours = this.time.getHours();
19409 var minutes = this.time.getMinutes();
19422 hours = hours - 12;
19426 hours = '0' + hours;
19430 minutes = '0' + minutes;
19433 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19434 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19435 this.pop.select('button', true).first().dom.innerHTML = period;
19441 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19443 var cls = ['bottom'];
19445 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19452 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19457 this.picker().addClass(cls.join('-'));
19461 Roo.each(cls, function(c){
19463 _this.picker().setTop(_this.inputEl().getHeight());
19467 _this.picker().setTop(0 - _this.picker().getHeight());
19472 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19476 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19483 onFocus : function()
19485 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19489 onBlur : function()
19491 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19497 this.picker().show();
19502 this.fireEvent('show', this, this.date);
19507 this.picker().hide();
19510 this.fireEvent('hide', this, this.date);
19513 setTime : function()
19516 this.setValue(this.time.format(this.format));
19518 this.fireEvent('select', this, this.date);
19523 onMousedown: function(e){
19524 e.stopPropagation();
19525 e.preventDefault();
19528 onIncrementHours: function()
19530 Roo.log('onIncrementHours');
19531 this.time = this.time.add(Date.HOUR, 1);
19536 onDecrementHours: function()
19538 Roo.log('onDecrementHours');
19539 this.time = this.time.add(Date.HOUR, -1);
19543 onIncrementMinutes: function()
19545 Roo.log('onIncrementMinutes');
19546 this.time = this.time.add(Date.MINUTE, 1);
19550 onDecrementMinutes: function()
19552 Roo.log('onDecrementMinutes');
19553 this.time = this.time.add(Date.MINUTE, -1);
19557 onTogglePeriod: function()
19559 Roo.log('onTogglePeriod');
19560 this.time = this.time.add(Date.HOUR, 12);
19567 Roo.apply(Roo.bootstrap.TimeField, {
19597 cls: 'btn btn-info ok',
19609 Roo.apply(Roo.bootstrap.TimeField, {
19613 cls: 'datepicker dropdown-menu',
19617 cls: 'datepicker-time',
19621 cls: 'table-condensed',
19623 Roo.bootstrap.TimeField.content,
19624 Roo.bootstrap.TimeField.footer
19643 * @class Roo.bootstrap.MonthField
19644 * @extends Roo.bootstrap.Input
19645 * Bootstrap MonthField class
19647 * @cfg {String} language default en
19650 * Create a new MonthField
19651 * @param {Object} config The config object
19654 Roo.bootstrap.MonthField = function(config){
19655 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19660 * Fires when this field show.
19661 * @param {Roo.bootstrap.MonthField} this
19662 * @param {Mixed} date The date value
19667 * Fires when this field hide.
19668 * @param {Roo.bootstrap.MonthField} this
19669 * @param {Mixed} date The date value
19674 * Fires when select a date.
19675 * @param {Roo.bootstrap.MonthField} this
19676 * @param {String} oldvalue The old value
19677 * @param {String} newvalue The new value
19683 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19685 onRender: function(ct, position)
19688 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19690 this.language = this.language || 'en';
19691 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19692 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19694 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19695 this.isInline = false;
19696 this.isInput = true;
19697 this.component = this.el.select('.add-on', true).first() || false;
19698 this.component = (this.component && this.component.length === 0) ? false : this.component;
19699 this.hasInput = this.component && this.inputEL().length;
19701 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19703 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19705 this.picker().on('mousedown', this.onMousedown, this);
19706 this.picker().on('click', this.onClick, this);
19708 this.picker().addClass('datepicker-dropdown');
19710 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19711 v.setStyle('width', '189px');
19718 if(this.isInline) {
19724 setValue: function(v, suppressEvent)
19726 var o = this.getValue();
19728 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19732 if(suppressEvent !== true){
19733 this.fireEvent('select', this, o, v);
19738 getValue: function()
19743 onClick: function(e)
19745 e.stopPropagation();
19746 e.preventDefault();
19748 var target = e.getTarget();
19750 if(target.nodeName.toLowerCase() === 'i'){
19751 target = Roo.get(target).dom.parentNode;
19754 var nodeName = target.nodeName;
19755 var className = target.className;
19756 var html = target.innerHTML;
19758 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19762 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19764 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19770 picker : function()
19772 return this.pickerEl;
19775 fillMonths: function()
19778 var months = this.picker().select('>.datepicker-months td', true).first();
19780 months.dom.innerHTML = '';
19786 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19789 months.createChild(month);
19798 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19799 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19802 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19803 e.removeClass('active');
19805 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19806 e.addClass('active');
19813 if(this.isInline) {
19817 this.picker().removeClass(['bottom', 'top']);
19819 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19821 * place to the top of element!
19825 this.picker().addClass('top');
19826 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19831 this.picker().addClass('bottom');
19833 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19836 onFocus : function()
19838 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19842 onBlur : function()
19844 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19846 var d = this.inputEl().getValue();
19855 this.picker().show();
19856 this.picker().select('>.datepicker-months', true).first().show();
19860 this.fireEvent('show', this, this.date);
19865 if(this.isInline) {
19868 this.picker().hide();
19869 this.fireEvent('hide', this, this.date);
19873 onMousedown: function(e)
19875 e.stopPropagation();
19876 e.preventDefault();
19881 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19885 fireKey: function(e)
19887 if (!this.picker().isVisible()){
19888 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19899 e.preventDefault();
19903 dir = e.keyCode == 37 ? -1 : 1;
19905 this.vIndex = this.vIndex + dir;
19907 if(this.vIndex < 0){
19911 if(this.vIndex > 11){
19915 if(isNaN(this.vIndex)){
19919 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19925 dir = e.keyCode == 38 ? -1 : 1;
19927 this.vIndex = this.vIndex + dir * 4;
19929 if(this.vIndex < 0){
19933 if(this.vIndex > 11){
19937 if(isNaN(this.vIndex)){
19941 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19946 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19947 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19951 e.preventDefault();
19954 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19955 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19971 this.picker().remove();
19976 Roo.apply(Roo.bootstrap.MonthField, {
19995 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19996 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20001 Roo.apply(Roo.bootstrap.MonthField, {
20005 cls: 'datepicker dropdown-menu roo-dynamic',
20009 cls: 'datepicker-months',
20013 cls: 'table-condensed',
20015 Roo.bootstrap.DateField.content
20035 * @class Roo.bootstrap.CheckBox
20036 * @extends Roo.bootstrap.Input
20037 * Bootstrap CheckBox class
20039 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20040 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20041 * @cfg {String} boxLabel The text that appears beside the checkbox
20042 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20043 * @cfg {Boolean} checked initnal the element
20044 * @cfg {Boolean} inline inline the element (default false)
20045 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20048 * Create a new CheckBox
20049 * @param {Object} config The config object
20052 Roo.bootstrap.CheckBox = function(config){
20053 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20058 * Fires when the element is checked or unchecked.
20059 * @param {Roo.bootstrap.CheckBox} this This input
20060 * @param {Boolean} checked The new checked value
20067 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20069 inputType: 'checkbox',
20077 getAutoCreate : function()
20079 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20085 cfg.cls = 'form-group ' + this.inputType; //input-group
20088 cfg.cls += ' ' + this.inputType + '-inline';
20094 type : this.inputType,
20095 value : this.inputValue,
20096 cls : 'roo-' + this.inputType, //'form-box',
20097 placeholder : this.placeholder || ''
20101 if(this.inputType != 'radio'){
20105 cls : 'roo-hidden-value',
20106 value : this.checked ? this.valueOff : this.inputValue
20111 if (this.weight) { // Validity check?
20112 cfg.cls += " " + this.inputType + "-" + this.weight;
20115 if (this.disabled) {
20116 input.disabled=true;
20120 input.checked = this.checked;
20127 input.name = this.name;
20129 if(this.inputType != 'radio'){
20130 hidden.name = this.name;
20131 input.name = '_hidden_' + this.name;
20136 input.cls += ' input-' + this.size;
20141 ['xs','sm','md','lg'].map(function(size){
20142 if (settings[size]) {
20143 cfg.cls += ' col-' + size + '-' + settings[size];
20147 var inputblock = input;
20149 if (this.before || this.after) {
20152 cls : 'input-group',
20157 inputblock.cn.push({
20159 cls : 'input-group-addon',
20164 inputblock.cn.push(input);
20166 if(this.inputType != 'radio'){
20167 inputblock.cn.push(hidden);
20171 inputblock.cn.push({
20173 cls : 'input-group-addon',
20180 if (align ==='left' && this.fieldLabel.length) {
20181 // Roo.log("left and has label");
20186 cls : 'control-label',
20187 html : this.fieldLabel
20198 if(this.labelWidth > 12){
20199 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20202 if(this.labelWidth < 13 && this.labelmd == 0){
20203 this.labelmd = this.labelWidth;
20206 if(this.labellg > 0){
20207 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20208 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20211 if(this.labelmd > 0){
20212 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20213 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20216 if(this.labelsm > 0){
20217 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20218 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20221 if(this.labelxs > 0){
20222 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20223 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20226 } else if ( this.fieldLabel.length) {
20227 // Roo.log(" label");
20231 tag: this.boxLabel ? 'span' : 'label',
20233 cls: 'control-label box-input-label',
20234 //cls : 'input-group-addon',
20235 html : this.fieldLabel
20245 // Roo.log(" no label && no align");
20246 cfg.cn = [ inputblock ] ;
20252 var boxLabelCfg = {
20254 //'for': id, // box label is handled by onclick - so no for...
20256 html: this.boxLabel
20260 boxLabelCfg.tooltip = this.tooltip;
20263 cfg.cn.push(boxLabelCfg);
20266 if(this.inputType != 'radio'){
20267 cfg.cn.push(hidden);
20275 * return the real input element.
20277 inputEl: function ()
20279 return this.el.select('input.roo-' + this.inputType,true).first();
20281 hiddenEl: function ()
20283 return this.el.select('input.roo-hidden-value',true).first();
20286 labelEl: function()
20288 return this.el.select('label.control-label',true).first();
20290 /* depricated... */
20294 return this.labelEl();
20297 boxLabelEl: function()
20299 return this.el.select('label.box-label',true).first();
20302 initEvents : function()
20304 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20306 this.inputEl().on('click', this.onClick, this);
20308 if (this.boxLabel) {
20309 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20312 this.startValue = this.getValue();
20315 Roo.bootstrap.CheckBox.register(this);
20319 onClick : function()
20321 this.setChecked(!this.checked);
20324 setChecked : function(state,suppressEvent)
20326 this.startValue = this.getValue();
20328 if(this.inputType == 'radio'){
20330 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20331 e.dom.checked = false;
20334 this.inputEl().dom.checked = true;
20336 this.inputEl().dom.value = this.inputValue;
20338 if(suppressEvent !== true){
20339 this.fireEvent('check', this, true);
20347 this.checked = state;
20349 this.inputEl().dom.checked = state;
20352 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20354 if(suppressEvent !== true){
20355 this.fireEvent('check', this, state);
20361 getValue : function()
20363 if(this.inputType == 'radio'){
20364 return this.getGroupValue();
20367 return this.hiddenEl().dom.value;
20371 getGroupValue : function()
20373 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20377 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20380 setValue : function(v,suppressEvent)
20382 if(this.inputType == 'radio'){
20383 this.setGroupValue(v, suppressEvent);
20387 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20392 setGroupValue : function(v, suppressEvent)
20394 this.startValue = this.getValue();
20396 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20397 e.dom.checked = false;
20399 if(e.dom.value == v){
20400 e.dom.checked = true;
20404 if(suppressEvent !== true){
20405 this.fireEvent('check', this, true);
20413 validate : function()
20417 (this.inputType == 'radio' && this.validateRadio()) ||
20418 (this.inputType == 'checkbox' && this.validateCheckbox())
20424 this.markInvalid();
20428 validateRadio : function()
20430 if(this.allowBlank){
20436 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20437 if(!e.dom.checked){
20449 validateCheckbox : function()
20452 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20453 //return (this.getValue() == this.inputValue) ? true : false;
20456 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20464 for(var i in group){
20469 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20476 * Mark this field as valid
20478 markValid : function()
20482 this.fireEvent('valid', this);
20484 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20487 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20494 if(this.inputType == 'radio'){
20495 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20496 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20497 e.findParent('.form-group', false, true).addClass(_this.validClass);
20504 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20505 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20509 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20515 for(var i in group){
20516 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20517 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20522 * Mark this field as invalid
20523 * @param {String} msg The validation message
20525 markInvalid : function(msg)
20527 if(this.allowBlank){
20533 this.fireEvent('invalid', this, msg);
20535 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20538 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20542 label.markInvalid();
20545 if(this.inputType == 'radio'){
20546 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20547 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20548 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20555 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20556 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20560 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20566 for(var i in group){
20567 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20568 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20573 clearInvalid : function()
20575 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20577 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20579 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20582 label.iconEl.removeClass(label.validClass);
20583 label.iconEl.removeClass(label.invalidClass);
20587 disable : function()
20589 if(this.inputType != 'radio'){
20590 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20597 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20598 _this.getActionEl().addClass(this.disabledClass);
20599 e.dom.disabled = true;
20603 this.disabled = true;
20604 this.fireEvent("disable", this);
20608 enable : function()
20610 if(this.inputType != 'radio'){
20611 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20618 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20619 _this.getActionEl().removeClass(this.disabledClass);
20620 e.dom.disabled = false;
20624 this.disabled = false;
20625 this.fireEvent("enable", this);
20631 Roo.apply(Roo.bootstrap.CheckBox, {
20636 * register a CheckBox Group
20637 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20639 register : function(checkbox)
20641 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20642 this.groups[checkbox.groupId] = {};
20645 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20649 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20653 * fetch a CheckBox Group based on the group ID
20654 * @param {string} the group ID
20655 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20657 get: function(groupId) {
20658 if (typeof(this.groups[groupId]) == 'undefined') {
20662 return this.groups[groupId] ;
20675 * @class Roo.bootstrap.Radio
20676 * @extends Roo.bootstrap.Component
20677 * Bootstrap Radio class
20678 * @cfg {String} boxLabel - the label associated
20679 * @cfg {String} value - the value of radio
20682 * Create a new Radio
20683 * @param {Object} config The config object
20685 Roo.bootstrap.Radio = function(config){
20686 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20690 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20696 getAutoCreate : function()
20700 cls : 'form-group radio',
20705 html : this.boxLabel
20713 initEvents : function()
20715 this.parent().register(this);
20717 this.el.on('click', this.onClick, this);
20721 onClick : function()
20723 this.setChecked(true);
20726 setChecked : function(state, suppressEvent)
20728 this.parent().setValue(this.value, suppressEvent);
20743 * @class Roo.bootstrap.SecurePass
20744 * @extends Roo.bootstrap.Input
20745 * Bootstrap SecurePass class
20749 * Create a new SecurePass
20750 * @param {Object} config The config object
20753 Roo.bootstrap.SecurePass = function (config) {
20754 // these go here, so the translation tool can replace them..
20756 PwdEmpty: "Please type a password, and then retype it to confirm.",
20757 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20758 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20759 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20760 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20761 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20762 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20763 TooWeak: "Your password is Too Weak."
20765 this.meterLabel = "Password strength:";
20766 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20767 this.meterClass = [
20768 "roo-password-meter-tooweak",
20769 "roo-password-meter-weak",
20770 "roo-password-meter-medium",
20771 "roo-password-meter-strong",
20772 "roo-password-meter-grey"
20777 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20780 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20782 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20784 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20785 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20786 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20787 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20788 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20789 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20790 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20800 * @cfg {String/Object} Label for the strength meter (defaults to
20801 * 'Password strength:')
20806 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20807 * ['Weak', 'Medium', 'Strong'])
20810 pwdStrengths: false,
20823 initEvents: function ()
20825 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20827 if (this.el.is('input[type=password]') && Roo.isSafari) {
20828 this.el.on('keydown', this.SafariOnKeyDown, this);
20831 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20834 onRender: function (ct, position)
20836 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20837 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20838 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20840 this.trigger.createChild({
20845 cls: 'roo-password-meter-grey col-xs-12',
20848 //width: this.meterWidth + 'px'
20852 cls: 'roo-password-meter-text'
20858 if (this.hideTrigger) {
20859 this.trigger.setDisplayed(false);
20861 this.setSize(this.width || '', this.height || '');
20864 onDestroy: function ()
20866 if (this.trigger) {
20867 this.trigger.removeAllListeners();
20868 this.trigger.remove();
20871 this.wrap.remove();
20873 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20876 checkStrength: function ()
20878 var pwd = this.inputEl().getValue();
20879 if (pwd == this._lastPwd) {
20884 if (this.ClientSideStrongPassword(pwd)) {
20886 } else if (this.ClientSideMediumPassword(pwd)) {
20888 } else if (this.ClientSideWeakPassword(pwd)) {
20894 Roo.log('strength1: ' + strength);
20896 //var pm = this.trigger.child('div/div/div').dom;
20897 var pm = this.trigger.child('div/div');
20898 pm.removeClass(this.meterClass);
20899 pm.addClass(this.meterClass[strength]);
20902 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20904 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20906 this._lastPwd = pwd;
20910 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20912 this._lastPwd = '';
20914 var pm = this.trigger.child('div/div');
20915 pm.removeClass(this.meterClass);
20916 pm.addClass('roo-password-meter-grey');
20919 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20922 this.inputEl().dom.type='password';
20925 validateValue: function (value)
20928 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20931 if (value.length == 0) {
20932 if (this.allowBlank) {
20933 this.clearInvalid();
20937 this.markInvalid(this.errors.PwdEmpty);
20938 this.errorMsg = this.errors.PwdEmpty;
20946 if ('[\x21-\x7e]*'.match(value)) {
20947 this.markInvalid(this.errors.PwdBadChar);
20948 this.errorMsg = this.errors.PwdBadChar;
20951 if (value.length < 6) {
20952 this.markInvalid(this.errors.PwdShort);
20953 this.errorMsg = this.errors.PwdShort;
20956 if (value.length > 16) {
20957 this.markInvalid(this.errors.PwdLong);
20958 this.errorMsg = this.errors.PwdLong;
20962 if (this.ClientSideStrongPassword(value)) {
20964 } else if (this.ClientSideMediumPassword(value)) {
20966 } else if (this.ClientSideWeakPassword(value)) {
20973 if (strength < 2) {
20974 //this.markInvalid(this.errors.TooWeak);
20975 this.errorMsg = this.errors.TooWeak;
20980 console.log('strength2: ' + strength);
20982 //var pm = this.trigger.child('div/div/div').dom;
20984 var pm = this.trigger.child('div/div');
20985 pm.removeClass(this.meterClass);
20986 pm.addClass(this.meterClass[strength]);
20988 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20990 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20992 this.errorMsg = '';
20996 CharacterSetChecks: function (type)
20999 this.fResult = false;
21002 isctype: function (character, type)
21005 case this.kCapitalLetter:
21006 if (character >= 'A' && character <= 'Z') {
21011 case this.kSmallLetter:
21012 if (character >= 'a' && character <= 'z') {
21018 if (character >= '0' && character <= '9') {
21023 case this.kPunctuation:
21024 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21035 IsLongEnough: function (pwd, size)
21037 return !(pwd == null || isNaN(size) || pwd.length < size);
21040 SpansEnoughCharacterSets: function (word, nb)
21042 if (!this.IsLongEnough(word, nb))
21047 var characterSetChecks = new Array(
21048 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21049 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21052 for (var index = 0; index < word.length; ++index) {
21053 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21054 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21055 characterSetChecks[nCharSet].fResult = true;
21062 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21063 if (characterSetChecks[nCharSet].fResult) {
21068 if (nCharSets < nb) {
21074 ClientSideStrongPassword: function (pwd)
21076 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21079 ClientSideMediumPassword: function (pwd)
21081 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21084 ClientSideWeakPassword: function (pwd)
21086 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21089 })//<script type="text/javascript">
21092 * Based Ext JS Library 1.1.1
21093 * Copyright(c) 2006-2007, Ext JS, LLC.
21099 * @class Roo.HtmlEditorCore
21100 * @extends Roo.Component
21101 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21103 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21106 Roo.HtmlEditorCore = function(config){
21109 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21114 * @event initialize
21115 * Fires when the editor is fully initialized (including the iframe)
21116 * @param {Roo.HtmlEditorCore} this
21121 * Fires when the editor is first receives the focus. Any insertion must wait
21122 * until after this event.
21123 * @param {Roo.HtmlEditorCore} this
21127 * @event beforesync
21128 * Fires before the textarea is updated with content from the editor iframe. Return false
21129 * to cancel the sync.
21130 * @param {Roo.HtmlEditorCore} this
21131 * @param {String} html
21135 * @event beforepush
21136 * Fires before the iframe editor is updated with content from the textarea. Return false
21137 * to cancel the push.
21138 * @param {Roo.HtmlEditorCore} this
21139 * @param {String} html
21144 * Fires when the textarea is updated with content from the editor iframe.
21145 * @param {Roo.HtmlEditorCore} this
21146 * @param {String} html
21151 * Fires when the iframe editor is updated with content from the textarea.
21152 * @param {Roo.HtmlEditorCore} this
21153 * @param {String} html
21158 * @event editorevent
21159 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21160 * @param {Roo.HtmlEditorCore} this
21166 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21168 // defaults : white / black...
21169 this.applyBlacklists();
21176 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21180 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21186 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21191 * @cfg {Number} height (in pixels)
21195 * @cfg {Number} width (in pixels)
21200 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21203 stylesheets: false,
21208 // private properties
21209 validationEvent : false,
21211 initialized : false,
21213 sourceEditMode : false,
21214 onFocus : Roo.emptyFn,
21216 hideMode:'offsets',
21220 // blacklist + whitelisted elements..
21227 * Protected method that will not generally be called directly. It
21228 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21229 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21231 getDocMarkup : function(){
21235 // inherit styels from page...??
21236 if (this.stylesheets === false) {
21238 Roo.get(document.head).select('style').each(function(node) {
21239 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21242 Roo.get(document.head).select('link').each(function(node) {
21243 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21246 } else if (!this.stylesheets.length) {
21248 st = '<style type="text/css">' +
21249 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21255 st += '<style type="text/css">' +
21256 'IMG { cursor: pointer } ' +
21260 return '<html><head>' + st +
21261 //<style type="text/css">' +
21262 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21264 ' </head><body class="roo-htmleditor-body"></body></html>';
21268 onRender : function(ct, position)
21271 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21272 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21275 this.el.dom.style.border = '0 none';
21276 this.el.dom.setAttribute('tabIndex', -1);
21277 this.el.addClass('x-hidden hide');
21281 if(Roo.isIE){ // fix IE 1px bogus margin
21282 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21286 this.frameId = Roo.id();
21290 var iframe = this.owner.wrap.createChild({
21292 cls: 'form-control', // bootstrap..
21294 name: this.frameId,
21295 frameBorder : 'no',
21296 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21301 this.iframe = iframe.dom;
21303 this.assignDocWin();
21305 this.doc.designMode = 'on';
21308 this.doc.write(this.getDocMarkup());
21312 var task = { // must defer to wait for browser to be ready
21314 //console.log("run task?" + this.doc.readyState);
21315 this.assignDocWin();
21316 if(this.doc.body || this.doc.readyState == 'complete'){
21318 this.doc.designMode="on";
21322 Roo.TaskMgr.stop(task);
21323 this.initEditor.defer(10, this);
21330 Roo.TaskMgr.start(task);
21335 onResize : function(w, h)
21337 Roo.log('resize: ' +w + ',' + h );
21338 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21342 if(typeof w == 'number'){
21344 this.iframe.style.width = w + 'px';
21346 if(typeof h == 'number'){
21348 this.iframe.style.height = h + 'px';
21350 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21357 * Toggles the editor between standard and source edit mode.
21358 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21360 toggleSourceEdit : function(sourceEditMode){
21362 this.sourceEditMode = sourceEditMode === true;
21364 if(this.sourceEditMode){
21366 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21369 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21370 //this.iframe.className = '';
21373 //this.setSize(this.owner.wrap.getSize());
21374 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21381 * Protected method that will not generally be called directly. If you need/want
21382 * custom HTML cleanup, this is the method you should override.
21383 * @param {String} html The HTML to be cleaned
21384 * return {String} The cleaned HTML
21386 cleanHtml : function(html){
21387 html = String(html);
21388 if(html.length > 5){
21389 if(Roo.isSafari){ // strip safari nonsense
21390 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21393 if(html == ' '){
21400 * HTML Editor -> Textarea
21401 * Protected method that will not generally be called directly. Syncs the contents
21402 * of the editor iframe with the textarea.
21404 syncValue : function(){
21405 if(this.initialized){
21406 var bd = (this.doc.body || this.doc.documentElement);
21407 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21408 var html = bd.innerHTML;
21410 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21411 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21413 html = '<div style="'+m[0]+'">' + html + '</div>';
21416 html = this.cleanHtml(html);
21417 // fix up the special chars.. normaly like back quotes in word...
21418 // however we do not want to do this with chinese..
21419 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21420 var cc = b.charCodeAt();
21422 (cc >= 0x4E00 && cc < 0xA000 ) ||
21423 (cc >= 0x3400 && cc < 0x4E00 ) ||
21424 (cc >= 0xf900 && cc < 0xfb00 )
21430 if(this.owner.fireEvent('beforesync', this, html) !== false){
21431 this.el.dom.value = html;
21432 this.owner.fireEvent('sync', this, html);
21438 * Protected method that will not generally be called directly. Pushes the value of the textarea
21439 * into the iframe editor.
21441 pushValue : function(){
21442 if(this.initialized){
21443 var v = this.el.dom.value.trim();
21445 // if(v.length < 1){
21449 if(this.owner.fireEvent('beforepush', this, v) !== false){
21450 var d = (this.doc.body || this.doc.documentElement);
21452 this.cleanUpPaste();
21453 this.el.dom.value = d.innerHTML;
21454 this.owner.fireEvent('push', this, v);
21460 deferFocus : function(){
21461 this.focus.defer(10, this);
21465 focus : function(){
21466 if(this.win && !this.sourceEditMode){
21473 assignDocWin: function()
21475 var iframe = this.iframe;
21478 this.doc = iframe.contentWindow.document;
21479 this.win = iframe.contentWindow;
21481 // if (!Roo.get(this.frameId)) {
21484 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21485 // this.win = Roo.get(this.frameId).dom.contentWindow;
21487 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21491 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21492 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21497 initEditor : function(){
21498 //console.log("INIT EDITOR");
21499 this.assignDocWin();
21503 this.doc.designMode="on";
21505 this.doc.write(this.getDocMarkup());
21508 var dbody = (this.doc.body || this.doc.documentElement);
21509 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21510 // this copies styles from the containing element into thsi one..
21511 // not sure why we need all of this..
21512 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21514 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21515 //ss['background-attachment'] = 'fixed'; // w3c
21516 dbody.bgProperties = 'fixed'; // ie
21517 //Roo.DomHelper.applyStyles(dbody, ss);
21518 Roo.EventManager.on(this.doc, {
21519 //'mousedown': this.onEditorEvent,
21520 'mouseup': this.onEditorEvent,
21521 'dblclick': this.onEditorEvent,
21522 'click': this.onEditorEvent,
21523 'keyup': this.onEditorEvent,
21528 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21530 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21531 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21533 this.initialized = true;
21535 this.owner.fireEvent('initialize', this);
21540 onDestroy : function(){
21546 //for (var i =0; i < this.toolbars.length;i++) {
21547 // // fixme - ask toolbars for heights?
21548 // this.toolbars[i].onDestroy();
21551 //this.wrap.dom.innerHTML = '';
21552 //this.wrap.remove();
21557 onFirstFocus : function(){
21559 this.assignDocWin();
21562 this.activated = true;
21565 if(Roo.isGecko){ // prevent silly gecko errors
21567 var s = this.win.getSelection();
21568 if(!s.focusNode || s.focusNode.nodeType != 3){
21569 var r = s.getRangeAt(0);
21570 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21575 this.execCmd('useCSS', true);
21576 this.execCmd('styleWithCSS', false);
21579 this.owner.fireEvent('activate', this);
21583 adjustFont: function(btn){
21584 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21585 //if(Roo.isSafari){ // safari
21588 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21589 if(Roo.isSafari){ // safari
21590 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21591 v = (v < 10) ? 10 : v;
21592 v = (v > 48) ? 48 : v;
21593 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21598 v = Math.max(1, v+adjust);
21600 this.execCmd('FontSize', v );
21603 onEditorEvent : function(e)
21605 this.owner.fireEvent('editorevent', this, e);
21606 // this.updateToolbar();
21607 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21610 insertTag : function(tg)
21612 // could be a bit smarter... -> wrap the current selected tRoo..
21613 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21615 range = this.createRange(this.getSelection());
21616 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21617 wrappingNode.appendChild(range.extractContents());
21618 range.insertNode(wrappingNode);
21625 this.execCmd("formatblock", tg);
21629 insertText : function(txt)
21633 var range = this.createRange();
21634 range.deleteContents();
21635 //alert(Sender.getAttribute('label'));
21637 range.insertNode(this.doc.createTextNode(txt));
21643 * Executes a Midas editor command on the editor document and performs necessary focus and
21644 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21645 * @param {String} cmd The Midas command
21646 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21648 relayCmd : function(cmd, value){
21650 this.execCmd(cmd, value);
21651 this.owner.fireEvent('editorevent', this);
21652 //this.updateToolbar();
21653 this.owner.deferFocus();
21657 * Executes a Midas editor command directly on the editor document.
21658 * For visual commands, you should use {@link #relayCmd} instead.
21659 * <b>This should only be called after the editor is initialized.</b>
21660 * @param {String} cmd The Midas command
21661 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21663 execCmd : function(cmd, value){
21664 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21671 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21673 * @param {String} text | dom node..
21675 insertAtCursor : function(text)
21678 if(!this.activated){
21684 var r = this.doc.selection.createRange();
21695 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21699 // from jquery ui (MIT licenced)
21701 var win = this.win;
21703 if (win.getSelection && win.getSelection().getRangeAt) {
21704 range = win.getSelection().getRangeAt(0);
21705 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21706 range.insertNode(node);
21707 } else if (win.document.selection && win.document.selection.createRange) {
21708 // no firefox support
21709 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21710 win.document.selection.createRange().pasteHTML(txt);
21712 // no firefox support
21713 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21714 this.execCmd('InsertHTML', txt);
21723 mozKeyPress : function(e){
21725 var c = e.getCharCode(), cmd;
21728 c = String.fromCharCode(c).toLowerCase();
21742 this.cleanUpPaste.defer(100, this);
21750 e.preventDefault();
21758 fixKeys : function(){ // load time branching for fastest keydown performance
21760 return function(e){
21761 var k = e.getKey(), r;
21764 r = this.doc.selection.createRange();
21767 r.pasteHTML('    ');
21774 r = this.doc.selection.createRange();
21776 var target = r.parentElement();
21777 if(!target || target.tagName.toLowerCase() != 'li'){
21779 r.pasteHTML('<br />');
21785 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21786 this.cleanUpPaste.defer(100, this);
21792 }else if(Roo.isOpera){
21793 return function(e){
21794 var k = e.getKey();
21798 this.execCmd('InsertHTML','    ');
21801 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21802 this.cleanUpPaste.defer(100, this);
21807 }else if(Roo.isSafari){
21808 return function(e){
21809 var k = e.getKey();
21813 this.execCmd('InsertText','\t');
21817 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21818 this.cleanUpPaste.defer(100, this);
21826 getAllAncestors: function()
21828 var p = this.getSelectedNode();
21831 a.push(p); // push blank onto stack..
21832 p = this.getParentElement();
21836 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21840 a.push(this.doc.body);
21844 lastSelNode : false,
21847 getSelection : function()
21849 this.assignDocWin();
21850 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21853 getSelectedNode: function()
21855 // this may only work on Gecko!!!
21857 // should we cache this!!!!
21862 var range = this.createRange(this.getSelection()).cloneRange();
21865 var parent = range.parentElement();
21867 var testRange = range.duplicate();
21868 testRange.moveToElementText(parent);
21869 if (testRange.inRange(range)) {
21872 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21875 parent = parent.parentElement;
21880 // is ancestor a text element.
21881 var ac = range.commonAncestorContainer;
21882 if (ac.nodeType == 3) {
21883 ac = ac.parentNode;
21886 var ar = ac.childNodes;
21889 var other_nodes = [];
21890 var has_other_nodes = false;
21891 for (var i=0;i<ar.length;i++) {
21892 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21895 // fullly contained node.
21897 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21902 // probably selected..
21903 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21904 other_nodes.push(ar[i]);
21908 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21913 has_other_nodes = true;
21915 if (!nodes.length && other_nodes.length) {
21916 nodes= other_nodes;
21918 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21924 createRange: function(sel)
21926 // this has strange effects when using with
21927 // top toolbar - not sure if it's a great idea.
21928 //this.editor.contentWindow.focus();
21929 if (typeof sel != "undefined") {
21931 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21933 return this.doc.createRange();
21936 return this.doc.createRange();
21939 getParentElement: function()
21942 this.assignDocWin();
21943 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21945 var range = this.createRange(sel);
21948 var p = range.commonAncestorContainer;
21949 while (p.nodeType == 3) { // text node
21960 * Range intersection.. the hard stuff...
21964 * [ -- selected range --- ]
21968 * if end is before start or hits it. fail.
21969 * if start is after end or hits it fail.
21971 * if either hits (but other is outside. - then it's not
21977 // @see http://www.thismuchiknow.co.uk/?p=64.
21978 rangeIntersectsNode : function(range, node)
21980 var nodeRange = node.ownerDocument.createRange();
21982 nodeRange.selectNode(node);
21984 nodeRange.selectNodeContents(node);
21987 var rangeStartRange = range.cloneRange();
21988 rangeStartRange.collapse(true);
21990 var rangeEndRange = range.cloneRange();
21991 rangeEndRange.collapse(false);
21993 var nodeStartRange = nodeRange.cloneRange();
21994 nodeStartRange.collapse(true);
21996 var nodeEndRange = nodeRange.cloneRange();
21997 nodeEndRange.collapse(false);
21999 return rangeStartRange.compareBoundaryPoints(
22000 Range.START_TO_START, nodeEndRange) == -1 &&
22001 rangeEndRange.compareBoundaryPoints(
22002 Range.START_TO_START, nodeStartRange) == 1;
22006 rangeCompareNode : function(range, node)
22008 var nodeRange = node.ownerDocument.createRange();
22010 nodeRange.selectNode(node);
22012 nodeRange.selectNodeContents(node);
22016 range.collapse(true);
22018 nodeRange.collapse(true);
22020 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22021 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22023 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22025 var nodeIsBefore = ss == 1;
22026 var nodeIsAfter = ee == -1;
22028 if (nodeIsBefore && nodeIsAfter) {
22031 if (!nodeIsBefore && nodeIsAfter) {
22032 return 1; //right trailed.
22035 if (nodeIsBefore && !nodeIsAfter) {
22036 return 2; // left trailed.
22042 // private? - in a new class?
22043 cleanUpPaste : function()
22045 // cleans up the whole document..
22046 Roo.log('cleanuppaste');
22048 this.cleanUpChildren(this.doc.body);
22049 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22050 if (clean != this.doc.body.innerHTML) {
22051 this.doc.body.innerHTML = clean;
22056 cleanWordChars : function(input) {// change the chars to hex code
22057 var he = Roo.HtmlEditorCore;
22059 var output = input;
22060 Roo.each(he.swapCodes, function(sw) {
22061 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22063 output = output.replace(swapper, sw[1]);
22070 cleanUpChildren : function (n)
22072 if (!n.childNodes.length) {
22075 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22076 this.cleanUpChild(n.childNodes[i]);
22083 cleanUpChild : function (node)
22086 //console.log(node);
22087 if (node.nodeName == "#text") {
22088 // clean up silly Windows -- stuff?
22091 if (node.nodeName == "#comment") {
22092 node.parentNode.removeChild(node);
22093 // clean up silly Windows -- stuff?
22096 var lcname = node.tagName.toLowerCase();
22097 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22098 // whitelist of tags..
22100 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22102 node.parentNode.removeChild(node);
22107 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22109 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22110 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22112 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22113 // remove_keep_children = true;
22116 if (remove_keep_children) {
22117 this.cleanUpChildren(node);
22118 // inserts everything just before this node...
22119 while (node.childNodes.length) {
22120 var cn = node.childNodes[0];
22121 node.removeChild(cn);
22122 node.parentNode.insertBefore(cn, node);
22124 node.parentNode.removeChild(node);
22128 if (!node.attributes || !node.attributes.length) {
22129 this.cleanUpChildren(node);
22133 function cleanAttr(n,v)
22136 if (v.match(/^\./) || v.match(/^\//)) {
22139 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22142 if (v.match(/^#/)) {
22145 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22146 node.removeAttribute(n);
22150 var cwhite = this.cwhite;
22151 var cblack = this.cblack;
22153 function cleanStyle(n,v)
22155 if (v.match(/expression/)) { //XSS?? should we even bother..
22156 node.removeAttribute(n);
22160 var parts = v.split(/;/);
22163 Roo.each(parts, function(p) {
22164 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22168 var l = p.split(':').shift().replace(/\s+/g,'');
22169 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22171 if ( cwhite.length && cblack.indexOf(l) > -1) {
22172 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22173 //node.removeAttribute(n);
22177 // only allow 'c whitelisted system attributes'
22178 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22179 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22180 //node.removeAttribute(n);
22190 if (clean.length) {
22191 node.setAttribute(n, clean.join(';'));
22193 node.removeAttribute(n);
22199 for (var i = node.attributes.length-1; i > -1 ; i--) {
22200 var a = node.attributes[i];
22203 if (a.name.toLowerCase().substr(0,2)=='on') {
22204 node.removeAttribute(a.name);
22207 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22208 node.removeAttribute(a.name);
22211 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22212 cleanAttr(a.name,a.value); // fixme..
22215 if (a.name == 'style') {
22216 cleanStyle(a.name,a.value);
22219 /// clean up MS crap..
22220 // tecnically this should be a list of valid class'es..
22223 if (a.name == 'class') {
22224 if (a.value.match(/^Mso/)) {
22225 node.className = '';
22228 if (a.value.match(/^body$/)) {
22229 node.className = '';
22240 this.cleanUpChildren(node);
22246 * Clean up MS wordisms...
22248 cleanWord : function(node)
22253 this.cleanWord(this.doc.body);
22256 if (node.nodeName == "#text") {
22257 // clean up silly Windows -- stuff?
22260 if (node.nodeName == "#comment") {
22261 node.parentNode.removeChild(node);
22262 // clean up silly Windows -- stuff?
22266 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22267 node.parentNode.removeChild(node);
22271 // remove - but keep children..
22272 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22273 while (node.childNodes.length) {
22274 var cn = node.childNodes[0];
22275 node.removeChild(cn);
22276 node.parentNode.insertBefore(cn, node);
22278 node.parentNode.removeChild(node);
22279 this.iterateChildren(node, this.cleanWord);
22283 if (node.className.length) {
22285 var cn = node.className.split(/\W+/);
22287 Roo.each(cn, function(cls) {
22288 if (cls.match(/Mso[a-zA-Z]+/)) {
22293 node.className = cna.length ? cna.join(' ') : '';
22295 node.removeAttribute("class");
22299 if (node.hasAttribute("lang")) {
22300 node.removeAttribute("lang");
22303 if (node.hasAttribute("style")) {
22305 var styles = node.getAttribute("style").split(";");
22307 Roo.each(styles, function(s) {
22308 if (!s.match(/:/)) {
22311 var kv = s.split(":");
22312 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22315 // what ever is left... we allow.
22318 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22319 if (!nstyle.length) {
22320 node.removeAttribute('style');
22323 this.iterateChildren(node, this.cleanWord);
22329 * iterateChildren of a Node, calling fn each time, using this as the scole..
22330 * @param {DomNode} node node to iterate children of.
22331 * @param {Function} fn method of this class to call on each item.
22333 iterateChildren : function(node, fn)
22335 if (!node.childNodes.length) {
22338 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22339 fn.call(this, node.childNodes[i])
22345 * cleanTableWidths.
22347 * Quite often pasting from word etc.. results in tables with column and widths.
22348 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22351 cleanTableWidths : function(node)
22356 this.cleanTableWidths(this.doc.body);
22361 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22364 Roo.log(node.tagName);
22365 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22366 this.iterateChildren(node, this.cleanTableWidths);
22369 if (node.hasAttribute('width')) {
22370 node.removeAttribute('width');
22374 if (node.hasAttribute("style")) {
22377 var styles = node.getAttribute("style").split(";");
22379 Roo.each(styles, function(s) {
22380 if (!s.match(/:/)) {
22383 var kv = s.split(":");
22384 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22387 // what ever is left... we allow.
22390 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22391 if (!nstyle.length) {
22392 node.removeAttribute('style');
22396 this.iterateChildren(node, this.cleanTableWidths);
22404 domToHTML : function(currentElement, depth, nopadtext) {
22406 depth = depth || 0;
22407 nopadtext = nopadtext || false;
22409 if (!currentElement) {
22410 return this.domToHTML(this.doc.body);
22413 //Roo.log(currentElement);
22415 var allText = false;
22416 var nodeName = currentElement.nodeName;
22417 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22419 if (nodeName == '#text') {
22421 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22426 if (nodeName != 'BODY') {
22429 // Prints the node tagName, such as <A>, <IMG>, etc
22432 for(i = 0; i < currentElement.attributes.length;i++) {
22434 var aname = currentElement.attributes.item(i).name;
22435 if (!currentElement.attributes.item(i).value.length) {
22438 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22441 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22450 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22453 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22458 // Traverse the tree
22460 var currentElementChild = currentElement.childNodes.item(i);
22461 var allText = true;
22462 var innerHTML = '';
22464 while (currentElementChild) {
22465 // Formatting code (indent the tree so it looks nice on the screen)
22466 var nopad = nopadtext;
22467 if (lastnode == 'SPAN') {
22471 if (currentElementChild.nodeName == '#text') {
22472 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22473 toadd = nopadtext ? toadd : toadd.trim();
22474 if (!nopad && toadd.length > 80) {
22475 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22477 innerHTML += toadd;
22480 currentElementChild = currentElement.childNodes.item(i);
22486 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22488 // Recursively traverse the tree structure of the child node
22489 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22490 lastnode = currentElementChild.nodeName;
22492 currentElementChild=currentElement.childNodes.item(i);
22498 // The remaining code is mostly for formatting the tree
22499 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22504 ret+= "</"+tagName+">";
22510 applyBlacklists : function()
22512 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22513 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22517 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22518 if (b.indexOf(tag) > -1) {
22521 this.white.push(tag);
22525 Roo.each(w, function(tag) {
22526 if (b.indexOf(tag) > -1) {
22529 if (this.white.indexOf(tag) > -1) {
22532 this.white.push(tag);
22537 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22538 if (w.indexOf(tag) > -1) {
22541 this.black.push(tag);
22545 Roo.each(b, function(tag) {
22546 if (w.indexOf(tag) > -1) {
22549 if (this.black.indexOf(tag) > -1) {
22552 this.black.push(tag);
22557 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22558 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22562 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22563 if (b.indexOf(tag) > -1) {
22566 this.cwhite.push(tag);
22570 Roo.each(w, function(tag) {
22571 if (b.indexOf(tag) > -1) {
22574 if (this.cwhite.indexOf(tag) > -1) {
22577 this.cwhite.push(tag);
22582 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22583 if (w.indexOf(tag) > -1) {
22586 this.cblack.push(tag);
22590 Roo.each(b, function(tag) {
22591 if (w.indexOf(tag) > -1) {
22594 if (this.cblack.indexOf(tag) > -1) {
22597 this.cblack.push(tag);
22602 setStylesheets : function(stylesheets)
22604 if(typeof(stylesheets) == 'string'){
22605 Roo.get(this.iframe.contentDocument.head).createChild({
22607 rel : 'stylesheet',
22616 Roo.each(stylesheets, function(s) {
22621 Roo.get(_this.iframe.contentDocument.head).createChild({
22623 rel : 'stylesheet',
22632 removeStylesheets : function()
22636 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22641 // hide stuff that is not compatible
22655 * @event specialkey
22659 * @cfg {String} fieldClass @hide
22662 * @cfg {String} focusClass @hide
22665 * @cfg {String} autoCreate @hide
22668 * @cfg {String} inputType @hide
22671 * @cfg {String} invalidClass @hide
22674 * @cfg {String} invalidText @hide
22677 * @cfg {String} msgFx @hide
22680 * @cfg {String} validateOnBlur @hide
22684 Roo.HtmlEditorCore.white = [
22685 'area', 'br', 'img', 'input', 'hr', 'wbr',
22687 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22688 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22689 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22690 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22691 'table', 'ul', 'xmp',
22693 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22696 'dir', 'menu', 'ol', 'ul', 'dl',
22702 Roo.HtmlEditorCore.black = [
22703 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22705 'base', 'basefont', 'bgsound', 'blink', 'body',
22706 'frame', 'frameset', 'head', 'html', 'ilayer',
22707 'iframe', 'layer', 'link', 'meta', 'object',
22708 'script', 'style' ,'title', 'xml' // clean later..
22710 Roo.HtmlEditorCore.clean = [
22711 'script', 'style', 'title', 'xml'
22713 Roo.HtmlEditorCore.remove = [
22718 Roo.HtmlEditorCore.ablack = [
22722 Roo.HtmlEditorCore.aclean = [
22723 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22727 Roo.HtmlEditorCore.pwhite= [
22728 'http', 'https', 'mailto'
22731 // white listed style attributes.
22732 Roo.HtmlEditorCore.cwhite= [
22733 // 'text-align', /// default is to allow most things..
22739 // black listed style attributes.
22740 Roo.HtmlEditorCore.cblack= [
22741 // 'font-size' -- this can be set by the project
22745 Roo.HtmlEditorCore.swapCodes =[
22764 * @class Roo.bootstrap.HtmlEditor
22765 * @extends Roo.bootstrap.TextArea
22766 * Bootstrap HtmlEditor class
22769 * Create a new HtmlEditor
22770 * @param {Object} config The config object
22773 Roo.bootstrap.HtmlEditor = function(config){
22774 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22775 if (!this.toolbars) {
22776 this.toolbars = [];
22779 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22782 * @event initialize
22783 * Fires when the editor is fully initialized (including the iframe)
22784 * @param {HtmlEditor} this
22789 * Fires when the editor is first receives the focus. Any insertion must wait
22790 * until after this event.
22791 * @param {HtmlEditor} this
22795 * @event beforesync
22796 * Fires before the textarea is updated with content from the editor iframe. Return false
22797 * to cancel the sync.
22798 * @param {HtmlEditor} this
22799 * @param {String} html
22803 * @event beforepush
22804 * Fires before the iframe editor is updated with content from the textarea. Return false
22805 * to cancel the push.
22806 * @param {HtmlEditor} this
22807 * @param {String} html
22812 * Fires when the textarea is updated with content from the editor iframe.
22813 * @param {HtmlEditor} this
22814 * @param {String} html
22819 * Fires when the iframe editor is updated with content from the textarea.
22820 * @param {HtmlEditor} this
22821 * @param {String} html
22825 * @event editmodechange
22826 * Fires when the editor switches edit modes
22827 * @param {HtmlEditor} this
22828 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22830 editmodechange: true,
22832 * @event editorevent
22833 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22834 * @param {HtmlEditor} this
22838 * @event firstfocus
22839 * Fires when on first focus - needed by toolbars..
22840 * @param {HtmlEditor} this
22845 * Auto save the htmlEditor value as a file into Events
22846 * @param {HtmlEditor} this
22850 * @event savedpreview
22851 * preview the saved version of htmlEditor
22852 * @param {HtmlEditor} this
22859 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22863 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22868 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
22873 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22878 * @cfg {Number} height (in pixels)
22882 * @cfg {Number} width (in pixels)
22887 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22890 stylesheets: false,
22895 // private properties
22896 validationEvent : false,
22898 initialized : false,
22901 onFocus : Roo.emptyFn,
22903 hideMode:'offsets',
22905 tbContainer : false,
22907 toolbarContainer :function() {
22908 return this.wrap.select('.x-html-editor-tb',true).first();
22912 * Protected method that will not generally be called directly. It
22913 * is called when the editor creates its toolbar. Override this method if you need to
22914 * add custom toolbar buttons.
22915 * @param {HtmlEditor} editor
22917 createToolbar : function(){
22918 Roo.log('renewing');
22919 Roo.log("create toolbars");
22921 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22922 this.toolbars[0].render(this.toolbarContainer());
22926 // if (!editor.toolbars || !editor.toolbars.length) {
22927 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22930 // for (var i =0 ; i < editor.toolbars.length;i++) {
22931 // editor.toolbars[i] = Roo.factory(
22932 // typeof(editor.toolbars[i]) == 'string' ?
22933 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22934 // Roo.bootstrap.HtmlEditor);
22935 // editor.toolbars[i].init(editor);
22941 onRender : function(ct, position)
22943 // Roo.log("Call onRender: " + this.xtype);
22945 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22947 this.wrap = this.inputEl().wrap({
22948 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22951 this.editorcore.onRender(ct, position);
22953 if (this.resizable) {
22954 this.resizeEl = new Roo.Resizable(this.wrap, {
22958 minHeight : this.height,
22959 height: this.height,
22960 handles : this.resizable,
22963 resize : function(r, w, h) {
22964 _t.onResize(w,h); // -something
22970 this.createToolbar(this);
22973 if(!this.width && this.resizable){
22974 this.setSize(this.wrap.getSize());
22976 if (this.resizeEl) {
22977 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22978 // should trigger onReize..
22984 onResize : function(w, h)
22986 Roo.log('resize: ' +w + ',' + h );
22987 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22991 if(this.inputEl() ){
22992 if(typeof w == 'number'){
22993 var aw = w - this.wrap.getFrameWidth('lr');
22994 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22997 if(typeof h == 'number'){
22998 var tbh = -11; // fixme it needs to tool bar size!
22999 for (var i =0; i < this.toolbars.length;i++) {
23000 // fixme - ask toolbars for heights?
23001 tbh += this.toolbars[i].el.getHeight();
23002 //if (this.toolbars[i].footer) {
23003 // tbh += this.toolbars[i].footer.el.getHeight();
23011 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23012 ah -= 5; // knock a few pixes off for look..
23013 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23017 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23018 this.editorcore.onResize(ew,eh);
23023 * Toggles the editor between standard and source edit mode.
23024 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23026 toggleSourceEdit : function(sourceEditMode)
23028 this.editorcore.toggleSourceEdit(sourceEditMode);
23030 if(this.editorcore.sourceEditMode){
23031 Roo.log('editor - showing textarea');
23034 // Roo.log(this.syncValue());
23036 this.inputEl().removeClass(['hide', 'x-hidden']);
23037 this.inputEl().dom.removeAttribute('tabIndex');
23038 this.inputEl().focus();
23040 Roo.log('editor - hiding textarea');
23042 // Roo.log(this.pushValue());
23045 this.inputEl().addClass(['hide', 'x-hidden']);
23046 this.inputEl().dom.setAttribute('tabIndex', -1);
23047 //this.deferFocus();
23050 if(this.resizable){
23051 this.setSize(this.wrap.getSize());
23054 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23057 // private (for BoxComponent)
23058 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23060 // private (for BoxComponent)
23061 getResizeEl : function(){
23065 // private (for BoxComponent)
23066 getPositionEl : function(){
23071 initEvents : function(){
23072 this.originalValue = this.getValue();
23076 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23079 // markInvalid : Roo.emptyFn,
23081 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23084 // clearInvalid : Roo.emptyFn,
23086 setValue : function(v){
23087 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23088 this.editorcore.pushValue();
23093 deferFocus : function(){
23094 this.focus.defer(10, this);
23098 focus : function(){
23099 this.editorcore.focus();
23105 onDestroy : function(){
23111 for (var i =0; i < this.toolbars.length;i++) {
23112 // fixme - ask toolbars for heights?
23113 this.toolbars[i].onDestroy();
23116 this.wrap.dom.innerHTML = '';
23117 this.wrap.remove();
23122 onFirstFocus : function(){
23123 //Roo.log("onFirstFocus");
23124 this.editorcore.onFirstFocus();
23125 for (var i =0; i < this.toolbars.length;i++) {
23126 this.toolbars[i].onFirstFocus();
23132 syncValue : function()
23134 this.editorcore.syncValue();
23137 pushValue : function()
23139 this.editorcore.pushValue();
23143 // hide stuff that is not compatible
23157 * @event specialkey
23161 * @cfg {String} fieldClass @hide
23164 * @cfg {String} focusClass @hide
23167 * @cfg {String} autoCreate @hide
23170 * @cfg {String} inputType @hide
23173 * @cfg {String} invalidClass @hide
23176 * @cfg {String} invalidText @hide
23179 * @cfg {String} msgFx @hide
23182 * @cfg {String} validateOnBlur @hide
23191 Roo.namespace('Roo.bootstrap.htmleditor');
23193 * @class Roo.bootstrap.HtmlEditorToolbar1
23198 new Roo.bootstrap.HtmlEditor({
23201 new Roo.bootstrap.HtmlEditorToolbar1({
23202 disable : { fonts: 1 , format: 1, ..., ... , ...],
23208 * @cfg {Object} disable List of elements to disable..
23209 * @cfg {Array} btns List of additional buttons.
23213 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23216 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23219 Roo.apply(this, config);
23221 // default disabled, based on 'good practice'..
23222 this.disable = this.disable || {};
23223 Roo.applyIf(this.disable, {
23226 specialElements : true
23228 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23230 this.editor = config.editor;
23231 this.editorcore = config.editor.editorcore;
23233 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23235 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23236 // dont call parent... till later.
23238 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23243 editorcore : false,
23248 "h1","h2","h3","h4","h5","h6",
23250 "abbr", "acronym", "address", "cite", "samp", "var",
23254 onRender : function(ct, position)
23256 // Roo.log("Call onRender: " + this.xtype);
23258 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23260 this.el.dom.style.marginBottom = '0';
23262 var editorcore = this.editorcore;
23263 var editor= this.editor;
23266 var btn = function(id,cmd , toggle, handler, html){
23268 var event = toggle ? 'toggle' : 'click';
23273 xns: Roo.bootstrap,
23276 enableToggle:toggle !== false,
23278 pressed : toggle ? false : null,
23281 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23282 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23288 // var cb_box = function...
23293 xns: Roo.bootstrap,
23294 glyphicon : 'font',
23298 xns: Roo.bootstrap,
23302 Roo.each(this.formats, function(f) {
23303 style.menu.items.push({
23305 xns: Roo.bootstrap,
23306 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23311 editorcore.insertTag(this.tagname);
23318 children.push(style);
23320 btn('bold',false,true);
23321 btn('italic',false,true);
23322 btn('align-left', 'justifyleft',true);
23323 btn('align-center', 'justifycenter',true);
23324 btn('align-right' , 'justifyright',true);
23325 btn('link', false, false, function(btn) {
23326 //Roo.log("create link?");
23327 var url = prompt(this.createLinkText, this.defaultLinkValue);
23328 if(url && url != 'http:/'+'/'){
23329 this.editorcore.relayCmd('createlink', url);
23332 btn('list','insertunorderedlist',true);
23333 btn('pencil', false,true, function(btn){
23335 this.toggleSourceEdit(btn.pressed);
23338 if (this.editor.btns.length > 0) {
23339 for (var i = 0; i<this.editor.btns.length; i++) {
23340 children.push(this.editor.btns[i]);
23348 xns: Roo.bootstrap,
23353 xns: Roo.bootstrap,
23358 cog.menu.items.push({
23360 xns: Roo.bootstrap,
23361 html : Clean styles,
23366 editorcore.insertTag(this.tagname);
23375 this.xtype = 'NavSimplebar';
23377 for(var i=0;i< children.length;i++) {
23379 this.buttons.add(this.addxtypeChild(children[i]));
23383 editor.on('editorevent', this.updateToolbar, this);
23385 onBtnClick : function(id)
23387 this.editorcore.relayCmd(id);
23388 this.editorcore.focus();
23392 * Protected method that will not generally be called directly. It triggers
23393 * a toolbar update by reading the markup state of the current selection in the editor.
23395 updateToolbar: function(){
23397 if(!this.editorcore.activated){
23398 this.editor.onFirstFocus(); // is this neeed?
23402 var btns = this.buttons;
23403 var doc = this.editorcore.doc;
23404 btns.get('bold').setActive(doc.queryCommandState('bold'));
23405 btns.get('italic').setActive(doc.queryCommandState('italic'));
23406 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23408 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23409 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23410 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23412 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23413 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23416 var ans = this.editorcore.getAllAncestors();
23417 if (this.formatCombo) {
23420 var store = this.formatCombo.store;
23421 this.formatCombo.setValue("");
23422 for (var i =0; i < ans.length;i++) {
23423 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23425 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23433 // hides menus... - so this cant be on a menu...
23434 Roo.bootstrap.MenuMgr.hideAll();
23436 Roo.bootstrap.MenuMgr.hideAll();
23437 //this.editorsyncValue();
23439 onFirstFocus: function() {
23440 this.buttons.each(function(item){
23444 toggleSourceEdit : function(sourceEditMode){
23447 if(sourceEditMode){
23448 Roo.log("disabling buttons");
23449 this.buttons.each( function(item){
23450 if(item.cmd != 'pencil'){
23456 Roo.log("enabling buttons");
23457 if(this.editorcore.initialized){
23458 this.buttons.each( function(item){
23464 Roo.log("calling toggole on editor");
23465 // tell the editor that it's been pressed..
23466 this.editor.toggleSourceEdit(sourceEditMode);
23476 * @class Roo.bootstrap.Table.AbstractSelectionModel
23477 * @extends Roo.util.Observable
23478 * Abstract base class for grid SelectionModels. It provides the interface that should be
23479 * implemented by descendant classes. This class should not be directly instantiated.
23482 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23483 this.locked = false;
23484 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23488 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23489 /** @ignore Called by the grid automatically. Do not call directly. */
23490 init : function(grid){
23496 * Locks the selections.
23499 this.locked = true;
23503 * Unlocks the selections.
23505 unlock : function(){
23506 this.locked = false;
23510 * Returns true if the selections are locked.
23511 * @return {Boolean}
23513 isLocked : function(){
23514 return this.locked;
23518 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23519 * @class Roo.bootstrap.Table.RowSelectionModel
23520 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23521 * It supports multiple selections and keyboard selection/navigation.
23523 * @param {Object} config
23526 Roo.bootstrap.Table.RowSelectionModel = function(config){
23527 Roo.apply(this, config);
23528 this.selections = new Roo.util.MixedCollection(false, function(o){
23533 this.lastActive = false;
23537 * @event selectionchange
23538 * Fires when the selection changes
23539 * @param {SelectionModel} this
23541 "selectionchange" : true,
23543 * @event afterselectionchange
23544 * Fires after the selection changes (eg. by key press or clicking)
23545 * @param {SelectionModel} this
23547 "afterselectionchange" : true,
23549 * @event beforerowselect
23550 * Fires when a row is selected being selected, return false to cancel.
23551 * @param {SelectionModel} this
23552 * @param {Number} rowIndex The selected index
23553 * @param {Boolean} keepExisting False if other selections will be cleared
23555 "beforerowselect" : true,
23558 * Fires when a row is selected.
23559 * @param {SelectionModel} this
23560 * @param {Number} rowIndex The selected index
23561 * @param {Roo.data.Record} r The record
23563 "rowselect" : true,
23565 * @event rowdeselect
23566 * Fires when a row is deselected.
23567 * @param {SelectionModel} this
23568 * @param {Number} rowIndex The selected index
23570 "rowdeselect" : true
23572 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23573 this.locked = false;
23576 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23578 * @cfg {Boolean} singleSelect
23579 * True to allow selection of only one row at a time (defaults to false)
23581 singleSelect : false,
23584 initEvents : function()
23587 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23588 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23589 //}else{ // allow click to work like normal
23590 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23592 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23593 this.grid.on("rowclick", this.handleMouseDown, this);
23595 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23596 "up" : function(e){
23598 this.selectPrevious(e.shiftKey);
23599 }else if(this.last !== false && this.lastActive !== false){
23600 var last = this.last;
23601 this.selectRange(this.last, this.lastActive-1);
23602 this.grid.getView().focusRow(this.lastActive);
23603 if(last !== false){
23607 this.selectFirstRow();
23609 this.fireEvent("afterselectionchange", this);
23611 "down" : function(e){
23613 this.selectNext(e.shiftKey);
23614 }else if(this.last !== false && this.lastActive !== false){
23615 var last = this.last;
23616 this.selectRange(this.last, this.lastActive+1);
23617 this.grid.getView().focusRow(this.lastActive);
23618 if(last !== false){
23622 this.selectFirstRow();
23624 this.fireEvent("afterselectionchange", this);
23628 this.grid.store.on('load', function(){
23629 this.selections.clear();
23632 var view = this.grid.view;
23633 view.on("refresh", this.onRefresh, this);
23634 view.on("rowupdated", this.onRowUpdated, this);
23635 view.on("rowremoved", this.onRemove, this);
23640 onRefresh : function()
23642 var ds = this.grid.store, i, v = this.grid.view;
23643 var s = this.selections;
23644 s.each(function(r){
23645 if((i = ds.indexOfId(r.id)) != -1){
23654 onRemove : function(v, index, r){
23655 this.selections.remove(r);
23659 onRowUpdated : function(v, index, r){
23660 if(this.isSelected(r)){
23661 v.onRowSelect(index);
23667 * @param {Array} records The records to select
23668 * @param {Boolean} keepExisting (optional) True to keep existing selections
23670 selectRecords : function(records, keepExisting)
23673 this.clearSelections();
23675 var ds = this.grid.store;
23676 for(var i = 0, len = records.length; i < len; i++){
23677 this.selectRow(ds.indexOf(records[i]), true);
23682 * Gets the number of selected rows.
23685 getCount : function(){
23686 return this.selections.length;
23690 * Selects the first row in the grid.
23692 selectFirstRow : function(){
23697 * Select the last row.
23698 * @param {Boolean} keepExisting (optional) True to keep existing selections
23700 selectLastRow : function(keepExisting){
23701 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23702 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23706 * Selects the row immediately following the last selected row.
23707 * @param {Boolean} keepExisting (optional) True to keep existing selections
23709 selectNext : function(keepExisting)
23711 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23712 this.selectRow(this.last+1, keepExisting);
23713 this.grid.getView().focusRow(this.last);
23718 * Selects the row that precedes the last selected row.
23719 * @param {Boolean} keepExisting (optional) True to keep existing selections
23721 selectPrevious : function(keepExisting){
23723 this.selectRow(this.last-1, keepExisting);
23724 this.grid.getView().focusRow(this.last);
23729 * Returns the selected records
23730 * @return {Array} Array of selected records
23732 getSelections : function(){
23733 return [].concat(this.selections.items);
23737 * Returns the first selected record.
23740 getSelected : function(){
23741 return this.selections.itemAt(0);
23746 * Clears all selections.
23748 clearSelections : function(fast)
23754 var ds = this.grid.store;
23755 var s = this.selections;
23756 s.each(function(r){
23757 this.deselectRow(ds.indexOfId(r.id));
23761 this.selections.clear();
23768 * Selects all rows.
23770 selectAll : function(){
23774 this.selections.clear();
23775 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23776 this.selectRow(i, true);
23781 * Returns True if there is a selection.
23782 * @return {Boolean}
23784 hasSelection : function(){
23785 return this.selections.length > 0;
23789 * Returns True if the specified row is selected.
23790 * @param {Number/Record} record The record or index of the record to check
23791 * @return {Boolean}
23793 isSelected : function(index){
23794 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23795 return (r && this.selections.key(r.id) ? true : false);
23799 * Returns True if the specified record id is selected.
23800 * @param {String} id The id of record to check
23801 * @return {Boolean}
23803 isIdSelected : function(id){
23804 return (this.selections.key(id) ? true : false);
23809 handleMouseDBClick : function(e, t){
23813 handleMouseDown : function(e, t)
23815 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23816 if(this.isLocked() || rowIndex < 0 ){
23819 if(e.shiftKey && this.last !== false){
23820 var last = this.last;
23821 this.selectRange(last, rowIndex, e.ctrlKey);
23822 this.last = last; // reset the last
23826 var isSelected = this.isSelected(rowIndex);
23827 //Roo.log("select row:" + rowIndex);
23829 this.deselectRow(rowIndex);
23831 this.selectRow(rowIndex, true);
23835 if(e.button !== 0 && isSelected){
23836 alert('rowIndex 2: ' + rowIndex);
23837 view.focusRow(rowIndex);
23838 }else if(e.ctrlKey && isSelected){
23839 this.deselectRow(rowIndex);
23840 }else if(!isSelected){
23841 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23842 view.focusRow(rowIndex);
23846 this.fireEvent("afterselectionchange", this);
23849 handleDragableRowClick : function(grid, rowIndex, e)
23851 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23852 this.selectRow(rowIndex, false);
23853 grid.view.focusRow(rowIndex);
23854 this.fireEvent("afterselectionchange", this);
23859 * Selects multiple rows.
23860 * @param {Array} rows Array of the indexes of the row to select
23861 * @param {Boolean} keepExisting (optional) True to keep existing selections
23863 selectRows : function(rows, keepExisting){
23865 this.clearSelections();
23867 for(var i = 0, len = rows.length; i < len; i++){
23868 this.selectRow(rows[i], true);
23873 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23874 * @param {Number} startRow The index of the first row in the range
23875 * @param {Number} endRow The index of the last row in the range
23876 * @param {Boolean} keepExisting (optional) True to retain existing selections
23878 selectRange : function(startRow, endRow, keepExisting){
23883 this.clearSelections();
23885 if(startRow <= endRow){
23886 for(var i = startRow; i <= endRow; i++){
23887 this.selectRow(i, true);
23890 for(var i = startRow; i >= endRow; i--){
23891 this.selectRow(i, true);
23897 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23898 * @param {Number} startRow The index of the first row in the range
23899 * @param {Number} endRow The index of the last row in the range
23901 deselectRange : function(startRow, endRow, preventViewNotify){
23905 for(var i = startRow; i <= endRow; i++){
23906 this.deselectRow(i, preventViewNotify);
23912 * @param {Number} row The index of the row to select
23913 * @param {Boolean} keepExisting (optional) True to keep existing selections
23915 selectRow : function(index, keepExisting, preventViewNotify)
23917 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23920 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23921 if(!keepExisting || this.singleSelect){
23922 this.clearSelections();
23925 var r = this.grid.store.getAt(index);
23926 //console.log('selectRow - record id :' + r.id);
23928 this.selections.add(r);
23929 this.last = this.lastActive = index;
23930 if(!preventViewNotify){
23931 var proxy = new Roo.Element(
23932 this.grid.getRowDom(index)
23934 proxy.addClass('bg-info info');
23936 this.fireEvent("rowselect", this, index, r);
23937 this.fireEvent("selectionchange", this);
23943 * @param {Number} row The index of the row to deselect
23945 deselectRow : function(index, preventViewNotify)
23950 if(this.last == index){
23953 if(this.lastActive == index){
23954 this.lastActive = false;
23957 var r = this.grid.store.getAt(index);
23962 this.selections.remove(r);
23963 //.console.log('deselectRow - record id :' + r.id);
23964 if(!preventViewNotify){
23966 var proxy = new Roo.Element(
23967 this.grid.getRowDom(index)
23969 proxy.removeClass('bg-info info');
23971 this.fireEvent("rowdeselect", this, index);
23972 this.fireEvent("selectionchange", this);
23976 restoreLast : function(){
23978 this.last = this._last;
23983 acceptsNav : function(row, col, cm){
23984 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23988 onEditorKey : function(field, e){
23989 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23994 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23996 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23998 }else if(k == e.ENTER && !e.ctrlKey){
24002 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24004 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24006 }else if(k == e.ESC){
24010 g.startEditing(newCell[0], newCell[1]);
24016 * Ext JS Library 1.1.1
24017 * Copyright(c) 2006-2007, Ext JS, LLC.
24019 * Originally Released Under LGPL - original licence link has changed is not relivant.
24022 * <script type="text/javascript">
24026 * @class Roo.bootstrap.PagingToolbar
24027 * @extends Roo.bootstrap.NavSimplebar
24028 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24030 * Create a new PagingToolbar
24031 * @param {Object} config The config object
24032 * @param {Roo.data.Store} store
24034 Roo.bootstrap.PagingToolbar = function(config)
24036 // old args format still supported... - xtype is prefered..
24037 // created from xtype...
24039 this.ds = config.dataSource;
24041 if (config.store && !this.ds) {
24042 this.store= Roo.factory(config.store, Roo.data);
24043 this.ds = this.store;
24044 this.ds.xmodule = this.xmodule || false;
24047 this.toolbarItems = [];
24048 if (config.items) {
24049 this.toolbarItems = config.items;
24052 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24057 this.bind(this.ds);
24060 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24064 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24066 * @cfg {Roo.data.Store} dataSource
24067 * The underlying data store providing the paged data
24070 * @cfg {String/HTMLElement/Element} container
24071 * container The id or element that will contain the toolbar
24074 * @cfg {Boolean} displayInfo
24075 * True to display the displayMsg (defaults to false)
24078 * @cfg {Number} pageSize
24079 * The number of records to display per page (defaults to 20)
24083 * @cfg {String} displayMsg
24084 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24086 displayMsg : 'Displaying {0} - {1} of {2}',
24088 * @cfg {String} emptyMsg
24089 * The message to display when no records are found (defaults to "No data to display")
24091 emptyMsg : 'No data to display',
24093 * Customizable piece of the default paging text (defaults to "Page")
24096 beforePageText : "Page",
24098 * Customizable piece of the default paging text (defaults to "of %0")
24101 afterPageText : "of {0}",
24103 * Customizable piece of the default paging text (defaults to "First Page")
24106 firstText : "First Page",
24108 * Customizable piece of the default paging text (defaults to "Previous Page")
24111 prevText : "Previous Page",
24113 * Customizable piece of the default paging text (defaults to "Next Page")
24116 nextText : "Next Page",
24118 * Customizable piece of the default paging text (defaults to "Last Page")
24121 lastText : "Last Page",
24123 * Customizable piece of the default paging text (defaults to "Refresh")
24126 refreshText : "Refresh",
24130 onRender : function(ct, position)
24132 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24133 this.navgroup.parentId = this.id;
24134 this.navgroup.onRender(this.el, null);
24135 // add the buttons to the navgroup
24137 if(this.displayInfo){
24138 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24139 this.displayEl = this.el.select('.x-paging-info', true).first();
24140 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24141 // this.displayEl = navel.el.select('span',true).first();
24147 Roo.each(_this.buttons, function(e){ // this might need to use render????
24148 Roo.factory(e).onRender(_this.el, null);
24152 Roo.each(_this.toolbarItems, function(e) {
24153 _this.navgroup.addItem(e);
24157 this.first = this.navgroup.addItem({
24158 tooltip: this.firstText,
24160 icon : 'fa fa-backward',
24162 preventDefault: true,
24163 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24166 this.prev = this.navgroup.addItem({
24167 tooltip: this.prevText,
24169 icon : 'fa fa-step-backward',
24171 preventDefault: true,
24172 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24174 //this.addSeparator();
24177 var field = this.navgroup.addItem( {
24179 cls : 'x-paging-position',
24181 html : this.beforePageText +
24182 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24183 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24186 this.field = field.el.select('input', true).first();
24187 this.field.on("keydown", this.onPagingKeydown, this);
24188 this.field.on("focus", function(){this.dom.select();});
24191 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24192 //this.field.setHeight(18);
24193 //this.addSeparator();
24194 this.next = this.navgroup.addItem({
24195 tooltip: this.nextText,
24197 html : ' <i class="fa fa-step-forward">',
24199 preventDefault: true,
24200 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24202 this.last = this.navgroup.addItem({
24203 tooltip: this.lastText,
24204 icon : 'fa fa-forward',
24207 preventDefault: true,
24208 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24210 //this.addSeparator();
24211 this.loading = this.navgroup.addItem({
24212 tooltip: this.refreshText,
24213 icon: 'fa fa-refresh',
24214 preventDefault: true,
24215 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24221 updateInfo : function(){
24222 if(this.displayEl){
24223 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24224 var msg = count == 0 ?
24228 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24230 this.displayEl.update(msg);
24235 onLoad : function(ds, r, o)
24237 this.cursor = o.params ? o.params.start : 0;
24238 var d = this.getPageData(),
24243 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24244 this.field.dom.value = ap;
24245 this.first.setDisabled(ap == 1);
24246 this.prev.setDisabled(ap == 1);
24247 this.next.setDisabled(ap == ps);
24248 this.last.setDisabled(ap == ps);
24249 this.loading.enable();
24254 getPageData : function(){
24255 var total = this.ds.getTotalCount();
24258 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24259 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24264 onLoadError : function(){
24265 this.loading.enable();
24269 onPagingKeydown : function(e){
24270 var k = e.getKey();
24271 var d = this.getPageData();
24273 var v = this.field.dom.value, pageNum;
24274 if(!v || isNaN(pageNum = parseInt(v, 10))){
24275 this.field.dom.value = d.activePage;
24278 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24279 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24282 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))
24284 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24285 this.field.dom.value = pageNum;
24286 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24289 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24291 var v = this.field.dom.value, pageNum;
24292 var increment = (e.shiftKey) ? 10 : 1;
24293 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24296 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24297 this.field.dom.value = d.activePage;
24300 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24302 this.field.dom.value = parseInt(v, 10) + increment;
24303 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24304 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24311 beforeLoad : function(){
24313 this.loading.disable();
24318 onClick : function(which){
24327 ds.load({params:{start: 0, limit: this.pageSize}});
24330 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24333 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24336 var total = ds.getTotalCount();
24337 var extra = total % this.pageSize;
24338 var lastStart = extra ? (total - extra) : total-this.pageSize;
24339 ds.load({params:{start: lastStart, limit: this.pageSize}});
24342 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24348 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24349 * @param {Roo.data.Store} store The data store to unbind
24351 unbind : function(ds){
24352 ds.un("beforeload", this.beforeLoad, this);
24353 ds.un("load", this.onLoad, this);
24354 ds.un("loadexception", this.onLoadError, this);
24355 ds.un("remove", this.updateInfo, this);
24356 ds.un("add", this.updateInfo, this);
24357 this.ds = undefined;
24361 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24362 * @param {Roo.data.Store} store The data store to bind
24364 bind : function(ds){
24365 ds.on("beforeload", this.beforeLoad, this);
24366 ds.on("load", this.onLoad, this);
24367 ds.on("loadexception", this.onLoadError, this);
24368 ds.on("remove", this.updateInfo, this);
24369 ds.on("add", this.updateInfo, this);
24380 * @class Roo.bootstrap.MessageBar
24381 * @extends Roo.bootstrap.Component
24382 * Bootstrap MessageBar class
24383 * @cfg {String} html contents of the MessageBar
24384 * @cfg {String} weight (info | success | warning | danger) default info
24385 * @cfg {String} beforeClass insert the bar before the given class
24386 * @cfg {Boolean} closable (true | false) default false
24387 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24390 * Create a new Element
24391 * @param {Object} config The config object
24394 Roo.bootstrap.MessageBar = function(config){
24395 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24398 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24404 beforeClass: 'bootstrap-sticky-wrap',
24406 getAutoCreate : function(){
24410 cls: 'alert alert-dismissable alert-' + this.weight,
24415 html: this.html || ''
24421 cfg.cls += ' alert-messages-fixed';
24435 onRender : function(ct, position)
24437 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24440 var cfg = Roo.apply({}, this.getAutoCreate());
24444 cfg.cls += ' ' + this.cls;
24447 cfg.style = this.style;
24449 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24451 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24454 this.el.select('>button.close').on('click', this.hide, this);
24460 if (!this.rendered) {
24466 this.fireEvent('show', this);
24472 if (!this.rendered) {
24478 this.fireEvent('hide', this);
24481 update : function()
24483 // var e = this.el.dom.firstChild;
24485 // if(this.closable){
24486 // e = e.nextSibling;
24489 // e.data = this.html || '';
24491 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24507 * @class Roo.bootstrap.Graph
24508 * @extends Roo.bootstrap.Component
24509 * Bootstrap Graph class
24513 @cfg {String} graphtype bar | vbar | pie
24514 @cfg {number} g_x coodinator | centre x (pie)
24515 @cfg {number} g_y coodinator | centre y (pie)
24516 @cfg {number} g_r radius (pie)
24517 @cfg {number} g_height height of the chart (respected by all elements in the set)
24518 @cfg {number} g_width width of the chart (respected by all elements in the set)
24519 @cfg {Object} title The title of the chart
24522 -opts (object) options for the chart
24524 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24525 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24527 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.
24528 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24530 o stretch (boolean)
24532 -opts (object) options for the pie
24535 o startAngle (number)
24536 o endAngle (number)
24540 * Create a new Input
24541 * @param {Object} config The config object
24544 Roo.bootstrap.Graph = function(config){
24545 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24551 * The img click event for the img.
24552 * @param {Roo.EventObject} e
24558 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24569 //g_colors: this.colors,
24576 getAutoCreate : function(){
24587 onRender : function(ct,position){
24590 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24592 if (typeof(Raphael) == 'undefined') {
24593 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24597 this.raphael = Raphael(this.el.dom);
24599 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24600 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24601 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24602 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24604 r.text(160, 10, "Single Series Chart").attr(txtattr);
24605 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24606 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24607 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24609 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24610 r.barchart(330, 10, 300, 220, data1);
24611 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24612 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24615 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24616 // r.barchart(30, 30, 560, 250, xdata, {
24617 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24618 // axis : "0 0 1 1",
24619 // axisxlabels : xdata
24620 // //yvalues : cols,
24623 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24625 // this.load(null,xdata,{
24626 // axis : "0 0 1 1",
24627 // axisxlabels : xdata
24632 load : function(graphtype,xdata,opts)
24634 this.raphael.clear();
24636 graphtype = this.graphtype;
24641 var r = this.raphael,
24642 fin = function () {
24643 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24645 fout = function () {
24646 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24648 pfin = function() {
24649 this.sector.stop();
24650 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24653 this.label[0].stop();
24654 this.label[0].attr({ r: 7.5 });
24655 this.label[1].attr({ "font-weight": 800 });
24658 pfout = function() {
24659 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24662 this.label[0].animate({ r: 5 }, 500, "bounce");
24663 this.label[1].attr({ "font-weight": 400 });
24669 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24672 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24675 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24676 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24678 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24685 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24690 setTitle: function(o)
24695 initEvents: function() {
24698 this.el.on('click', this.onClick, this);
24702 onClick : function(e)
24704 Roo.log('img onclick');
24705 this.fireEvent('click', this, e);
24717 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24720 * @class Roo.bootstrap.dash.NumberBox
24721 * @extends Roo.bootstrap.Component
24722 * Bootstrap NumberBox class
24723 * @cfg {String} headline Box headline
24724 * @cfg {String} content Box content
24725 * @cfg {String} icon Box icon
24726 * @cfg {String} footer Footer text
24727 * @cfg {String} fhref Footer href
24730 * Create a new NumberBox
24731 * @param {Object} config The config object
24735 Roo.bootstrap.dash.NumberBox = function(config){
24736 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24740 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24749 getAutoCreate : function(){
24753 cls : 'small-box ',
24761 cls : 'roo-headline',
24762 html : this.headline
24766 cls : 'roo-content',
24767 html : this.content
24781 cls : 'ion ' + this.icon
24790 cls : 'small-box-footer',
24791 href : this.fhref || '#',
24795 cfg.cn.push(footer);
24802 onRender : function(ct,position){
24803 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24810 setHeadline: function (value)
24812 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24815 setFooter: function (value, href)
24817 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24820 this.el.select('a.small-box-footer',true).first().attr('href', href);
24825 setContent: function (value)
24827 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24830 initEvents: function()
24844 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24847 * @class Roo.bootstrap.dash.TabBox
24848 * @extends Roo.bootstrap.Component
24849 * Bootstrap TabBox class
24850 * @cfg {String} title Title of the TabBox
24851 * @cfg {String} icon Icon of the TabBox
24852 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24853 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24856 * Create a new TabBox
24857 * @param {Object} config The config object
24861 Roo.bootstrap.dash.TabBox = function(config){
24862 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24867 * When a pane is added
24868 * @param {Roo.bootstrap.dash.TabPane} pane
24872 * @event activatepane
24873 * When a pane is activated
24874 * @param {Roo.bootstrap.dash.TabPane} pane
24876 "activatepane" : true
24884 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24889 tabScrollable : false,
24891 getChildContainer : function()
24893 return this.el.select('.tab-content', true).first();
24896 getAutoCreate : function(){
24900 cls: 'pull-left header',
24908 cls: 'fa ' + this.icon
24914 cls: 'nav nav-tabs pull-right',
24920 if(this.tabScrollable){
24927 cls: 'nav nav-tabs pull-right',
24938 cls: 'nav-tabs-custom',
24943 cls: 'tab-content no-padding',
24951 initEvents : function()
24953 //Roo.log('add add pane handler');
24954 this.on('addpane', this.onAddPane, this);
24957 * Updates the box title
24958 * @param {String} html to set the title to.
24960 setTitle : function(value)
24962 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24964 onAddPane : function(pane)
24966 this.panes.push(pane);
24967 //Roo.log('addpane');
24969 // tabs are rendere left to right..
24970 if(!this.showtabs){
24974 var ctr = this.el.select('.nav-tabs', true).first();
24977 var existing = ctr.select('.nav-tab',true);
24978 var qty = existing.getCount();;
24981 var tab = ctr.createChild({
24983 cls : 'nav-tab' + (qty ? '' : ' active'),
24991 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24994 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24996 pane.el.addClass('active');
25001 onTabClick : function(ev,un,ob,pane)
25003 //Roo.log('tab - prev default');
25004 ev.preventDefault();
25007 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25008 pane.tab.addClass('active');
25009 //Roo.log(pane.title);
25010 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25011 // technically we should have a deactivate event.. but maybe add later.
25012 // and it should not de-activate the selected tab...
25013 this.fireEvent('activatepane', pane);
25014 pane.el.addClass('active');
25015 pane.fireEvent('activate');
25020 getActivePane : function()
25023 Roo.each(this.panes, function(p) {
25024 if(p.el.hasClass('active')){
25045 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25047 * @class Roo.bootstrap.TabPane
25048 * @extends Roo.bootstrap.Component
25049 * Bootstrap TabPane class
25050 * @cfg {Boolean} active (false | true) Default false
25051 * @cfg {String} title title of panel
25055 * Create a new TabPane
25056 * @param {Object} config The config object
25059 Roo.bootstrap.dash.TabPane = function(config){
25060 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25066 * When a pane is activated
25067 * @param {Roo.bootstrap.dash.TabPane} pane
25074 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25079 // the tabBox that this is attached to.
25082 getAutoCreate : function()
25090 cfg.cls += ' active';
25095 initEvents : function()
25097 //Roo.log('trigger add pane handler');
25098 this.parent().fireEvent('addpane', this)
25102 * Updates the tab title
25103 * @param {String} html to set the title to.
25105 setTitle: function(str)
25111 this.tab.select('a', true).first().dom.innerHTML = str;
25128 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25131 * @class Roo.bootstrap.menu.Menu
25132 * @extends Roo.bootstrap.Component
25133 * Bootstrap Menu class - container for Menu
25134 * @cfg {String} html Text of the menu
25135 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25136 * @cfg {String} icon Font awesome icon
25137 * @cfg {String} pos Menu align to (top | bottom) default bottom
25141 * Create a new Menu
25142 * @param {Object} config The config object
25146 Roo.bootstrap.menu.Menu = function(config){
25147 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25151 * @event beforeshow
25152 * Fires before this menu is displayed
25153 * @param {Roo.bootstrap.menu.Menu} this
25157 * @event beforehide
25158 * Fires before this menu is hidden
25159 * @param {Roo.bootstrap.menu.Menu} this
25164 * Fires after this menu is displayed
25165 * @param {Roo.bootstrap.menu.Menu} this
25170 * Fires after this menu is hidden
25171 * @param {Roo.bootstrap.menu.Menu} this
25176 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25177 * @param {Roo.bootstrap.menu.Menu} this
25178 * @param {Roo.EventObject} e
25185 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25189 weight : 'default',
25194 getChildContainer : function() {
25195 if(this.isSubMenu){
25199 return this.el.select('ul.dropdown-menu', true).first();
25202 getAutoCreate : function()
25207 cls : 'roo-menu-text',
25215 cls : 'fa ' + this.icon
25226 cls : 'dropdown-button btn btn-' + this.weight,
25231 cls : 'dropdown-toggle btn btn-' + this.weight,
25241 cls : 'dropdown-menu'
25247 if(this.pos == 'top'){
25248 cfg.cls += ' dropup';
25251 if(this.isSubMenu){
25254 cls : 'dropdown-menu'
25261 onRender : function(ct, position)
25263 this.isSubMenu = ct.hasClass('dropdown-submenu');
25265 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25268 initEvents : function()
25270 if(this.isSubMenu){
25274 this.hidden = true;
25276 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25277 this.triggerEl.on('click', this.onTriggerPress, this);
25279 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25280 this.buttonEl.on('click', this.onClick, this);
25286 if(this.isSubMenu){
25290 return this.el.select('ul.dropdown-menu', true).first();
25293 onClick : function(e)
25295 this.fireEvent("click", this, e);
25298 onTriggerPress : function(e)
25300 if (this.isVisible()) {
25307 isVisible : function(){
25308 return !this.hidden;
25313 this.fireEvent("beforeshow", this);
25315 this.hidden = false;
25316 this.el.addClass('open');
25318 Roo.get(document).on("mouseup", this.onMouseUp, this);
25320 this.fireEvent("show", this);
25327 this.fireEvent("beforehide", this);
25329 this.hidden = true;
25330 this.el.removeClass('open');
25332 Roo.get(document).un("mouseup", this.onMouseUp);
25334 this.fireEvent("hide", this);
25337 onMouseUp : function()
25351 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25354 * @class Roo.bootstrap.menu.Item
25355 * @extends Roo.bootstrap.Component
25356 * Bootstrap MenuItem class
25357 * @cfg {Boolean} submenu (true | false) default false
25358 * @cfg {String} html text of the item
25359 * @cfg {String} href the link
25360 * @cfg {Boolean} disable (true | false) default false
25361 * @cfg {Boolean} preventDefault (true | false) default true
25362 * @cfg {String} icon Font awesome icon
25363 * @cfg {String} pos Submenu align to (left | right) default right
25367 * Create a new Item
25368 * @param {Object} config The config object
25372 Roo.bootstrap.menu.Item = function(config){
25373 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25377 * Fires when the mouse is hovering over this menu
25378 * @param {Roo.bootstrap.menu.Item} this
25379 * @param {Roo.EventObject} e
25384 * Fires when the mouse exits this menu
25385 * @param {Roo.bootstrap.menu.Item} this
25386 * @param {Roo.EventObject} e
25392 * The raw click event for the entire grid.
25393 * @param {Roo.EventObject} e
25399 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25404 preventDefault: true,
25409 getAutoCreate : function()
25414 cls : 'roo-menu-item-text',
25422 cls : 'fa ' + this.icon
25431 href : this.href || '#',
25438 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25442 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25444 if(this.pos == 'left'){
25445 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25452 initEvents : function()
25454 this.el.on('mouseover', this.onMouseOver, this);
25455 this.el.on('mouseout', this.onMouseOut, this);
25457 this.el.select('a', true).first().on('click', this.onClick, this);
25461 onClick : function(e)
25463 if(this.preventDefault){
25464 e.preventDefault();
25467 this.fireEvent("click", this, e);
25470 onMouseOver : function(e)
25472 if(this.submenu && this.pos == 'left'){
25473 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25476 this.fireEvent("mouseover", this, e);
25479 onMouseOut : function(e)
25481 this.fireEvent("mouseout", this, e);
25493 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25496 * @class Roo.bootstrap.menu.Separator
25497 * @extends Roo.bootstrap.Component
25498 * Bootstrap Separator class
25501 * Create a new Separator
25502 * @param {Object} config The config object
25506 Roo.bootstrap.menu.Separator = function(config){
25507 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25510 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25512 getAutoCreate : function(){
25533 * @class Roo.bootstrap.Tooltip
25534 * Bootstrap Tooltip class
25535 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25536 * to determine which dom element triggers the tooltip.
25538 * It needs to add support for additional attributes like tooltip-position
25541 * Create a new Toolti
25542 * @param {Object} config The config object
25545 Roo.bootstrap.Tooltip = function(config){
25546 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25548 this.alignment = Roo.bootstrap.Tooltip.alignment;
25550 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25551 this.alignment = config.alignment;
25556 Roo.apply(Roo.bootstrap.Tooltip, {
25558 * @function init initialize tooltip monitoring.
25562 currentTip : false,
25563 currentRegion : false,
25569 Roo.get(document).on('mouseover', this.enter ,this);
25570 Roo.get(document).on('mouseout', this.leave, this);
25573 this.currentTip = new Roo.bootstrap.Tooltip();
25576 enter : function(ev)
25578 var dom = ev.getTarget();
25580 //Roo.log(['enter',dom]);
25581 var el = Roo.fly(dom);
25582 if (this.currentEl) {
25584 //Roo.log(this.currentEl);
25585 //Roo.log(this.currentEl.contains(dom));
25586 if (this.currentEl == el) {
25589 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25595 if (this.currentTip.el) {
25596 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25600 if(!el || el.dom == document){
25606 // you can not look for children, as if el is the body.. then everythign is the child..
25607 if (!el.attr('tooltip')) { //
25608 if (!el.select("[tooltip]").elements.length) {
25611 // is the mouse over this child...?
25612 bindEl = el.select("[tooltip]").first();
25613 var xy = ev.getXY();
25614 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25615 //Roo.log("not in region.");
25618 //Roo.log("child element over..");
25621 this.currentEl = bindEl;
25622 this.currentTip.bind(bindEl);
25623 this.currentRegion = Roo.lib.Region.getRegion(dom);
25624 this.currentTip.enter();
25627 leave : function(ev)
25629 var dom = ev.getTarget();
25630 //Roo.log(['leave',dom]);
25631 if (!this.currentEl) {
25636 if (dom != this.currentEl.dom) {
25639 var xy = ev.getXY();
25640 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25643 // only activate leave if mouse cursor is outside... bounding box..
25648 if (this.currentTip) {
25649 this.currentTip.leave();
25651 //Roo.log('clear currentEl');
25652 this.currentEl = false;
25657 'left' : ['r-l', [-2,0], 'right'],
25658 'right' : ['l-r', [2,0], 'left'],
25659 'bottom' : ['t-b', [0,2], 'top'],
25660 'top' : [ 'b-t', [0,-2], 'bottom']
25666 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25671 delay : null, // can be { show : 300 , hide: 500}
25675 hoverState : null, //???
25677 placement : 'bottom',
25681 getAutoCreate : function(){
25688 cls : 'tooltip-arrow'
25691 cls : 'tooltip-inner'
25698 bind : function(el)
25704 enter : function () {
25706 if (this.timeout != null) {
25707 clearTimeout(this.timeout);
25710 this.hoverState = 'in';
25711 //Roo.log("enter - show");
25712 if (!this.delay || !this.delay.show) {
25717 this.timeout = setTimeout(function () {
25718 if (_t.hoverState == 'in') {
25721 }, this.delay.show);
25725 clearTimeout(this.timeout);
25727 this.hoverState = 'out';
25728 if (!this.delay || !this.delay.hide) {
25734 this.timeout = setTimeout(function () {
25735 //Roo.log("leave - timeout");
25737 if (_t.hoverState == 'out') {
25739 Roo.bootstrap.Tooltip.currentEl = false;
25744 show : function (msg)
25747 this.render(document.body);
25750 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25752 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25754 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25756 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25758 var placement = typeof this.placement == 'function' ?
25759 this.placement.call(this, this.el, on_el) :
25762 var autoToken = /\s?auto?\s?/i;
25763 var autoPlace = autoToken.test(placement);
25765 placement = placement.replace(autoToken, '') || 'top';
25769 //this.el.setXY([0,0]);
25771 //this.el.dom.style.display='block';
25773 //this.el.appendTo(on_el);
25775 var p = this.getPosition();
25776 var box = this.el.getBox();
25782 var align = this.alignment[placement];
25784 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25786 if(placement == 'top' || placement == 'bottom'){
25788 placement = 'right';
25791 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25792 placement = 'left';
25795 var scroll = Roo.select('body', true).first().getScroll();
25797 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25803 this.el.alignTo(this.bindEl, align[0],align[1]);
25804 //var arrow = this.el.select('.arrow',true).first();
25805 //arrow.set(align[2],
25807 this.el.addClass(placement);
25809 this.el.addClass('in fade');
25811 this.hoverState = null;
25813 if (this.el.hasClass('fade')) {
25824 //this.el.setXY([0,0]);
25825 this.el.removeClass('in');
25841 * @class Roo.bootstrap.LocationPicker
25842 * @extends Roo.bootstrap.Component
25843 * Bootstrap LocationPicker class
25844 * @cfg {Number} latitude Position when init default 0
25845 * @cfg {Number} longitude Position when init default 0
25846 * @cfg {Number} zoom default 15
25847 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25848 * @cfg {Boolean} mapTypeControl default false
25849 * @cfg {Boolean} disableDoubleClickZoom default false
25850 * @cfg {Boolean} scrollwheel default true
25851 * @cfg {Boolean} streetViewControl default false
25852 * @cfg {Number} radius default 0
25853 * @cfg {String} locationName
25854 * @cfg {Boolean} draggable default true
25855 * @cfg {Boolean} enableAutocomplete default false
25856 * @cfg {Boolean} enableReverseGeocode default true
25857 * @cfg {String} markerTitle
25860 * Create a new LocationPicker
25861 * @param {Object} config The config object
25865 Roo.bootstrap.LocationPicker = function(config){
25867 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25872 * Fires when the picker initialized.
25873 * @param {Roo.bootstrap.LocationPicker} this
25874 * @param {Google Location} location
25878 * @event positionchanged
25879 * Fires when the picker position changed.
25880 * @param {Roo.bootstrap.LocationPicker} this
25881 * @param {Google Location} location
25883 positionchanged : true,
25886 * Fires when the map resize.
25887 * @param {Roo.bootstrap.LocationPicker} this
25892 * Fires when the map show.
25893 * @param {Roo.bootstrap.LocationPicker} this
25898 * Fires when the map hide.
25899 * @param {Roo.bootstrap.LocationPicker} this
25904 * Fires when click the map.
25905 * @param {Roo.bootstrap.LocationPicker} this
25906 * @param {Map event} e
25910 * @event mapRightClick
25911 * Fires when right click the map.
25912 * @param {Roo.bootstrap.LocationPicker} this
25913 * @param {Map event} e
25915 mapRightClick : true,
25917 * @event markerClick
25918 * Fires when click the marker.
25919 * @param {Roo.bootstrap.LocationPicker} this
25920 * @param {Map event} e
25922 markerClick : true,
25924 * @event markerRightClick
25925 * Fires when right click the marker.
25926 * @param {Roo.bootstrap.LocationPicker} this
25927 * @param {Map event} e
25929 markerRightClick : true,
25931 * @event OverlayViewDraw
25932 * Fires when OverlayView Draw
25933 * @param {Roo.bootstrap.LocationPicker} this
25935 OverlayViewDraw : true,
25937 * @event OverlayViewOnAdd
25938 * Fires when OverlayView Draw
25939 * @param {Roo.bootstrap.LocationPicker} this
25941 OverlayViewOnAdd : true,
25943 * @event OverlayViewOnRemove
25944 * Fires when OverlayView Draw
25945 * @param {Roo.bootstrap.LocationPicker} this
25947 OverlayViewOnRemove : true,
25949 * @event OverlayViewShow
25950 * Fires when OverlayView Draw
25951 * @param {Roo.bootstrap.LocationPicker} this
25952 * @param {Pixel} cpx
25954 OverlayViewShow : true,
25956 * @event OverlayViewHide
25957 * Fires when OverlayView Draw
25958 * @param {Roo.bootstrap.LocationPicker} this
25960 OverlayViewHide : true,
25962 * @event loadexception
25963 * Fires when load google lib failed.
25964 * @param {Roo.bootstrap.LocationPicker} this
25966 loadexception : true
25971 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25973 gMapContext: false,
25979 mapTypeControl: false,
25980 disableDoubleClickZoom: false,
25982 streetViewControl: false,
25986 enableAutocomplete: false,
25987 enableReverseGeocode: true,
25990 getAutoCreate: function()
25995 cls: 'roo-location-picker'
26001 initEvents: function(ct, position)
26003 if(!this.el.getWidth() || this.isApplied()){
26007 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26012 initial: function()
26014 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26015 this.fireEvent('loadexception', this);
26019 if(!this.mapTypeId){
26020 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26023 this.gMapContext = this.GMapContext();
26025 this.initOverlayView();
26027 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26031 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26032 _this.setPosition(_this.gMapContext.marker.position);
26035 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26036 _this.fireEvent('mapClick', this, event);
26040 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26041 _this.fireEvent('mapRightClick', this, event);
26045 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26046 _this.fireEvent('markerClick', this, event);
26050 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26051 _this.fireEvent('markerRightClick', this, event);
26055 this.setPosition(this.gMapContext.location);
26057 this.fireEvent('initial', this, this.gMapContext.location);
26060 initOverlayView: function()
26064 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26068 _this.fireEvent('OverlayViewDraw', _this);
26073 _this.fireEvent('OverlayViewOnAdd', _this);
26076 onRemove: function()
26078 _this.fireEvent('OverlayViewOnRemove', _this);
26081 show: function(cpx)
26083 _this.fireEvent('OverlayViewShow', _this, cpx);
26088 _this.fireEvent('OverlayViewHide', _this);
26094 fromLatLngToContainerPixel: function(event)
26096 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26099 isApplied: function()
26101 return this.getGmapContext() == false ? false : true;
26104 getGmapContext: function()
26106 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26109 GMapContext: function()
26111 var position = new google.maps.LatLng(this.latitude, this.longitude);
26113 var _map = new google.maps.Map(this.el.dom, {
26116 mapTypeId: this.mapTypeId,
26117 mapTypeControl: this.mapTypeControl,
26118 disableDoubleClickZoom: this.disableDoubleClickZoom,
26119 scrollwheel: this.scrollwheel,
26120 streetViewControl: this.streetViewControl,
26121 locationName: this.locationName,
26122 draggable: this.draggable,
26123 enableAutocomplete: this.enableAutocomplete,
26124 enableReverseGeocode: this.enableReverseGeocode
26127 var _marker = new google.maps.Marker({
26128 position: position,
26130 title: this.markerTitle,
26131 draggable: this.draggable
26138 location: position,
26139 radius: this.radius,
26140 locationName: this.locationName,
26141 addressComponents: {
26142 formatted_address: null,
26143 addressLine1: null,
26144 addressLine2: null,
26146 streetNumber: null,
26150 stateOrProvince: null
26153 domContainer: this.el.dom,
26154 geodecoder: new google.maps.Geocoder()
26158 drawCircle: function(center, radius, options)
26160 if (this.gMapContext.circle != null) {
26161 this.gMapContext.circle.setMap(null);
26165 options = Roo.apply({}, options, {
26166 strokeColor: "#0000FF",
26167 strokeOpacity: .35,
26169 fillColor: "#0000FF",
26173 options.map = this.gMapContext.map;
26174 options.radius = radius;
26175 options.center = center;
26176 this.gMapContext.circle = new google.maps.Circle(options);
26177 return this.gMapContext.circle;
26183 setPosition: function(location)
26185 this.gMapContext.location = location;
26186 this.gMapContext.marker.setPosition(location);
26187 this.gMapContext.map.panTo(location);
26188 this.drawCircle(location, this.gMapContext.radius, {});
26192 if (this.gMapContext.settings.enableReverseGeocode) {
26193 this.gMapContext.geodecoder.geocode({
26194 latLng: this.gMapContext.location
26195 }, function(results, status) {
26197 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26198 _this.gMapContext.locationName = results[0].formatted_address;
26199 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26201 _this.fireEvent('positionchanged', this, location);
26208 this.fireEvent('positionchanged', this, location);
26213 google.maps.event.trigger(this.gMapContext.map, "resize");
26215 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26217 this.fireEvent('resize', this);
26220 setPositionByLatLng: function(latitude, longitude)
26222 this.setPosition(new google.maps.LatLng(latitude, longitude));
26225 getCurrentPosition: function()
26228 latitude: this.gMapContext.location.lat(),
26229 longitude: this.gMapContext.location.lng()
26233 getAddressName: function()
26235 return this.gMapContext.locationName;
26238 getAddressComponents: function()
26240 return this.gMapContext.addressComponents;
26243 address_component_from_google_geocode: function(address_components)
26247 for (var i = 0; i < address_components.length; i++) {
26248 var component = address_components[i];
26249 if (component.types.indexOf("postal_code") >= 0) {
26250 result.postalCode = component.short_name;
26251 } else if (component.types.indexOf("street_number") >= 0) {
26252 result.streetNumber = component.short_name;
26253 } else if (component.types.indexOf("route") >= 0) {
26254 result.streetName = component.short_name;
26255 } else if (component.types.indexOf("neighborhood") >= 0) {
26256 result.city = component.short_name;
26257 } else if (component.types.indexOf("locality") >= 0) {
26258 result.city = component.short_name;
26259 } else if (component.types.indexOf("sublocality") >= 0) {
26260 result.district = component.short_name;
26261 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26262 result.stateOrProvince = component.short_name;
26263 } else if (component.types.indexOf("country") >= 0) {
26264 result.country = component.short_name;
26268 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26269 result.addressLine2 = "";
26273 setZoomLevel: function(zoom)
26275 this.gMapContext.map.setZoom(zoom);
26288 this.fireEvent('show', this);
26299 this.fireEvent('hide', this);
26304 Roo.apply(Roo.bootstrap.LocationPicker, {
26306 OverlayView : function(map, options)
26308 options = options || {};
26322 * @class Roo.bootstrap.Alert
26323 * @extends Roo.bootstrap.Component
26324 * Bootstrap Alert class
26325 * @cfg {String} title The title of alert
26326 * @cfg {String} html The content of alert
26327 * @cfg {String} weight ( success | info | warning | danger )
26328 * @cfg {String} faicon font-awesomeicon
26331 * Create a new alert
26332 * @param {Object} config The config object
26336 Roo.bootstrap.Alert = function(config){
26337 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26341 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26348 getAutoCreate : function()
26357 cls : 'roo-alert-icon'
26362 cls : 'roo-alert-title',
26367 cls : 'roo-alert-text',
26374 cfg.cn[0].cls += ' fa ' + this.faicon;
26378 cfg.cls += ' alert-' + this.weight;
26384 initEvents: function()
26386 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26389 setTitle : function(str)
26391 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26394 setText : function(str)
26396 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26399 setWeight : function(weight)
26402 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26405 this.weight = weight;
26407 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26410 setIcon : function(icon)
26413 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26416 this.faicon = icon;
26418 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26439 * @class Roo.bootstrap.UploadCropbox
26440 * @extends Roo.bootstrap.Component
26441 * Bootstrap UploadCropbox class
26442 * @cfg {String} emptyText show when image has been loaded
26443 * @cfg {String} rotateNotify show when image too small to rotate
26444 * @cfg {Number} errorTimeout default 3000
26445 * @cfg {Number} minWidth default 300
26446 * @cfg {Number} minHeight default 300
26447 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26448 * @cfg {Boolean} isDocument (true|false) default false
26449 * @cfg {String} url action url
26450 * @cfg {String} paramName default 'imageUpload'
26451 * @cfg {String} method default POST
26452 * @cfg {Boolean} loadMask (true|false) default true
26453 * @cfg {Boolean} loadingText default 'Loading...'
26456 * Create a new UploadCropbox
26457 * @param {Object} config The config object
26460 Roo.bootstrap.UploadCropbox = function(config){
26461 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26465 * @event beforeselectfile
26466 * Fire before select file
26467 * @param {Roo.bootstrap.UploadCropbox} this
26469 "beforeselectfile" : true,
26472 * Fire after initEvent
26473 * @param {Roo.bootstrap.UploadCropbox} this
26478 * Fire after initEvent
26479 * @param {Roo.bootstrap.UploadCropbox} this
26480 * @param {String} data
26485 * Fire when preparing the file data
26486 * @param {Roo.bootstrap.UploadCropbox} this
26487 * @param {Object} file
26492 * Fire when get exception
26493 * @param {Roo.bootstrap.UploadCropbox} this
26494 * @param {XMLHttpRequest} xhr
26496 "exception" : true,
26498 * @event beforeloadcanvas
26499 * Fire before load the canvas
26500 * @param {Roo.bootstrap.UploadCropbox} this
26501 * @param {String} src
26503 "beforeloadcanvas" : true,
26506 * Fire when trash image
26507 * @param {Roo.bootstrap.UploadCropbox} this
26512 * Fire when download the image
26513 * @param {Roo.bootstrap.UploadCropbox} this
26517 * @event footerbuttonclick
26518 * Fire when footerbuttonclick
26519 * @param {Roo.bootstrap.UploadCropbox} this
26520 * @param {String} type
26522 "footerbuttonclick" : true,
26526 * @param {Roo.bootstrap.UploadCropbox} this
26531 * Fire when rotate the image
26532 * @param {Roo.bootstrap.UploadCropbox} this
26533 * @param {String} pos
26538 * Fire when inspect the file
26539 * @param {Roo.bootstrap.UploadCropbox} this
26540 * @param {Object} file
26545 * Fire when xhr upload the file
26546 * @param {Roo.bootstrap.UploadCropbox} this
26547 * @param {Object} data
26552 * Fire when arrange the file data
26553 * @param {Roo.bootstrap.UploadCropbox} this
26554 * @param {Object} formData
26559 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26562 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26564 emptyText : 'Click to upload image',
26565 rotateNotify : 'Image is too small to rotate',
26566 errorTimeout : 3000,
26580 cropType : 'image/jpeg',
26582 canvasLoaded : false,
26583 isDocument : false,
26585 paramName : 'imageUpload',
26587 loadingText : 'Loading...',
26590 getAutoCreate : function()
26594 cls : 'roo-upload-cropbox',
26598 cls : 'roo-upload-cropbox-selector',
26603 cls : 'roo-upload-cropbox-body',
26604 style : 'cursor:pointer',
26608 cls : 'roo-upload-cropbox-preview'
26612 cls : 'roo-upload-cropbox-thumb'
26616 cls : 'roo-upload-cropbox-empty-notify',
26617 html : this.emptyText
26621 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26622 html : this.rotateNotify
26628 cls : 'roo-upload-cropbox-footer',
26631 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26641 onRender : function(ct, position)
26643 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26645 if (this.buttons.length) {
26647 Roo.each(this.buttons, function(bb) {
26649 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26651 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26657 this.maskEl = this.el;
26661 initEvents : function()
26663 this.urlAPI = (window.createObjectURL && window) ||
26664 (window.URL && URL.revokeObjectURL && URL) ||
26665 (window.webkitURL && webkitURL);
26667 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26668 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26670 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26671 this.selectorEl.hide();
26673 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26674 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26676 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26677 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26678 this.thumbEl.hide();
26680 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26681 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26683 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26684 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26685 this.errorEl.hide();
26687 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26688 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26689 this.footerEl.hide();
26691 this.setThumbBoxSize();
26697 this.fireEvent('initial', this);
26704 window.addEventListener("resize", function() { _this.resize(); } );
26706 this.bodyEl.on('click', this.beforeSelectFile, this);
26709 this.bodyEl.on('touchstart', this.onTouchStart, this);
26710 this.bodyEl.on('touchmove', this.onTouchMove, this);
26711 this.bodyEl.on('touchend', this.onTouchEnd, this);
26715 this.bodyEl.on('mousedown', this.onMouseDown, this);
26716 this.bodyEl.on('mousemove', this.onMouseMove, this);
26717 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26718 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26719 Roo.get(document).on('mouseup', this.onMouseUp, this);
26722 this.selectorEl.on('change', this.onFileSelected, this);
26728 this.baseScale = 1;
26730 this.baseRotate = 1;
26731 this.dragable = false;
26732 this.pinching = false;
26735 this.cropData = false;
26736 this.notifyEl.dom.innerHTML = this.emptyText;
26738 this.selectorEl.dom.value = '';
26742 resize : function()
26744 if(this.fireEvent('resize', this) != false){
26745 this.setThumbBoxPosition();
26746 this.setCanvasPosition();
26750 onFooterButtonClick : function(e, el, o, type)
26753 case 'rotate-left' :
26754 this.onRotateLeft(e);
26756 case 'rotate-right' :
26757 this.onRotateRight(e);
26760 this.beforeSelectFile(e);
26775 this.fireEvent('footerbuttonclick', this, type);
26778 beforeSelectFile : function(e)
26780 e.preventDefault();
26782 if(this.fireEvent('beforeselectfile', this) != false){
26783 this.selectorEl.dom.click();
26787 onFileSelected : function(e)
26789 e.preventDefault();
26791 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26795 var file = this.selectorEl.dom.files[0];
26797 if(this.fireEvent('inspect', this, file) != false){
26798 this.prepare(file);
26803 trash : function(e)
26805 this.fireEvent('trash', this);
26808 download : function(e)
26810 this.fireEvent('download', this);
26813 loadCanvas : function(src)
26815 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26819 this.imageEl = document.createElement('img');
26823 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26825 this.imageEl.src = src;
26829 onLoadCanvas : function()
26831 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26832 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26834 this.bodyEl.un('click', this.beforeSelectFile, this);
26836 this.notifyEl.hide();
26837 this.thumbEl.show();
26838 this.footerEl.show();
26840 this.baseRotateLevel();
26842 if(this.isDocument){
26843 this.setThumbBoxSize();
26846 this.setThumbBoxPosition();
26848 this.baseScaleLevel();
26854 this.canvasLoaded = true;
26857 this.maskEl.unmask();
26862 setCanvasPosition : function()
26864 if(!this.canvasEl){
26868 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26869 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26871 this.previewEl.setLeft(pw);
26872 this.previewEl.setTop(ph);
26876 onMouseDown : function(e)
26880 this.dragable = true;
26881 this.pinching = false;
26883 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26884 this.dragable = false;
26888 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26889 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26893 onMouseMove : function(e)
26897 if(!this.canvasLoaded){
26901 if (!this.dragable){
26905 var minX = Math.ceil(this.thumbEl.getLeft(true));
26906 var minY = Math.ceil(this.thumbEl.getTop(true));
26908 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26909 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26911 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26912 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26914 x = x - this.mouseX;
26915 y = y - this.mouseY;
26917 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26918 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26920 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26921 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26923 this.previewEl.setLeft(bgX);
26924 this.previewEl.setTop(bgY);
26926 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26927 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26930 onMouseUp : function(e)
26934 this.dragable = false;
26937 onMouseWheel : function(e)
26941 this.startScale = this.scale;
26943 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26945 if(!this.zoomable()){
26946 this.scale = this.startScale;
26955 zoomable : function()
26957 var minScale = this.thumbEl.getWidth() / this.minWidth;
26959 if(this.minWidth < this.minHeight){
26960 minScale = this.thumbEl.getHeight() / this.minHeight;
26963 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26964 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26968 (this.rotate == 0 || this.rotate == 180) &&
26970 width > this.imageEl.OriginWidth ||
26971 height > this.imageEl.OriginHeight ||
26972 (width < this.minWidth && height < this.minHeight)
26980 (this.rotate == 90 || this.rotate == 270) &&
26982 width > this.imageEl.OriginWidth ||
26983 height > this.imageEl.OriginHeight ||
26984 (width < this.minHeight && height < this.minWidth)
26991 !this.isDocument &&
26992 (this.rotate == 0 || this.rotate == 180) &&
26994 width < this.minWidth ||
26995 width > this.imageEl.OriginWidth ||
26996 height < this.minHeight ||
26997 height > this.imageEl.OriginHeight
27004 !this.isDocument &&
27005 (this.rotate == 90 || this.rotate == 270) &&
27007 width < this.minHeight ||
27008 width > this.imageEl.OriginWidth ||
27009 height < this.minWidth ||
27010 height > this.imageEl.OriginHeight
27020 onRotateLeft : function(e)
27022 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27024 var minScale = this.thumbEl.getWidth() / this.minWidth;
27026 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27027 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27029 this.startScale = this.scale;
27031 while (this.getScaleLevel() < minScale){
27033 this.scale = this.scale + 1;
27035 if(!this.zoomable()){
27040 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27041 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27046 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27053 this.scale = this.startScale;
27055 this.onRotateFail();
27060 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27062 if(this.isDocument){
27063 this.setThumbBoxSize();
27064 this.setThumbBoxPosition();
27065 this.setCanvasPosition();
27070 this.fireEvent('rotate', this, 'left');
27074 onRotateRight : function(e)
27076 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27078 var minScale = this.thumbEl.getWidth() / this.minWidth;
27080 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27081 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27083 this.startScale = this.scale;
27085 while (this.getScaleLevel() < minScale){
27087 this.scale = this.scale + 1;
27089 if(!this.zoomable()){
27094 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27095 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27100 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27107 this.scale = this.startScale;
27109 this.onRotateFail();
27114 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27116 if(this.isDocument){
27117 this.setThumbBoxSize();
27118 this.setThumbBoxPosition();
27119 this.setCanvasPosition();
27124 this.fireEvent('rotate', this, 'right');
27127 onRotateFail : function()
27129 this.errorEl.show(true);
27133 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27138 this.previewEl.dom.innerHTML = '';
27140 var canvasEl = document.createElement("canvas");
27142 var contextEl = canvasEl.getContext("2d");
27144 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27145 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27146 var center = this.imageEl.OriginWidth / 2;
27148 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27149 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27150 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27151 center = this.imageEl.OriginHeight / 2;
27154 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27156 contextEl.translate(center, center);
27157 contextEl.rotate(this.rotate * Math.PI / 180);
27159 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27161 this.canvasEl = document.createElement("canvas");
27163 this.contextEl = this.canvasEl.getContext("2d");
27165 switch (this.rotate) {
27168 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27169 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27171 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27176 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27177 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27179 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27180 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);
27184 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27189 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27190 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27192 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27193 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);
27197 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);
27202 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27203 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27205 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27206 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27210 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);
27217 this.previewEl.appendChild(this.canvasEl);
27219 this.setCanvasPosition();
27224 if(!this.canvasLoaded){
27228 var imageCanvas = document.createElement("canvas");
27230 var imageContext = imageCanvas.getContext("2d");
27232 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27233 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27235 var center = imageCanvas.width / 2;
27237 imageContext.translate(center, center);
27239 imageContext.rotate(this.rotate * Math.PI / 180);
27241 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27243 var canvas = document.createElement("canvas");
27245 var context = canvas.getContext("2d");
27247 canvas.width = this.minWidth;
27248 canvas.height = this.minHeight;
27250 switch (this.rotate) {
27253 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27254 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27256 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27257 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27259 var targetWidth = this.minWidth - 2 * x;
27260 var targetHeight = this.minHeight - 2 * y;
27264 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27265 scale = targetWidth / width;
27268 if(x > 0 && y == 0){
27269 scale = targetHeight / height;
27272 if(x > 0 && y > 0){
27273 scale = targetWidth / width;
27275 if(width < height){
27276 scale = targetHeight / height;
27280 context.scale(scale, scale);
27282 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27283 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27285 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27286 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27288 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27293 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27294 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27296 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27297 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27299 var targetWidth = this.minWidth - 2 * x;
27300 var targetHeight = this.minHeight - 2 * y;
27304 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27305 scale = targetWidth / width;
27308 if(x > 0 && y == 0){
27309 scale = targetHeight / height;
27312 if(x > 0 && y > 0){
27313 scale = targetWidth / width;
27315 if(width < height){
27316 scale = targetHeight / height;
27320 context.scale(scale, scale);
27322 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27323 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27325 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27326 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27328 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27330 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27335 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27336 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27338 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27339 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27341 var targetWidth = this.minWidth - 2 * x;
27342 var targetHeight = this.minHeight - 2 * y;
27346 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27347 scale = targetWidth / width;
27350 if(x > 0 && y == 0){
27351 scale = targetHeight / height;
27354 if(x > 0 && y > 0){
27355 scale = targetWidth / width;
27357 if(width < height){
27358 scale = targetHeight / height;
27362 context.scale(scale, scale);
27364 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27365 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27367 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27368 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27370 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27371 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27373 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27378 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27379 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27381 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27382 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27384 var targetWidth = this.minWidth - 2 * x;
27385 var targetHeight = this.minHeight - 2 * y;
27389 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27390 scale = targetWidth / width;
27393 if(x > 0 && y == 0){
27394 scale = targetHeight / height;
27397 if(x > 0 && y > 0){
27398 scale = targetWidth / width;
27400 if(width < height){
27401 scale = targetHeight / height;
27405 context.scale(scale, scale);
27407 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27408 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27410 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27411 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27413 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27415 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27422 this.cropData = canvas.toDataURL(this.cropType);
27424 if(this.fireEvent('crop', this, this.cropData) !== false){
27425 this.process(this.file, this.cropData);
27432 setThumbBoxSize : function()
27436 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27437 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27438 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27440 this.minWidth = width;
27441 this.minHeight = height;
27443 if(this.rotate == 90 || this.rotate == 270){
27444 this.minWidth = height;
27445 this.minHeight = width;
27450 width = Math.ceil(this.minWidth * height / this.minHeight);
27452 if(this.minWidth > this.minHeight){
27454 height = Math.ceil(this.minHeight * width / this.minWidth);
27457 this.thumbEl.setStyle({
27458 width : width + 'px',
27459 height : height + 'px'
27466 setThumbBoxPosition : function()
27468 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27469 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27471 this.thumbEl.setLeft(x);
27472 this.thumbEl.setTop(y);
27476 baseRotateLevel : function()
27478 this.baseRotate = 1;
27481 typeof(this.exif) != 'undefined' &&
27482 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27483 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27485 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27488 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27492 baseScaleLevel : function()
27496 if(this.isDocument){
27498 if(this.baseRotate == 6 || this.baseRotate == 8){
27500 height = this.thumbEl.getHeight();
27501 this.baseScale = height / this.imageEl.OriginWidth;
27503 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27504 width = this.thumbEl.getWidth();
27505 this.baseScale = width / this.imageEl.OriginHeight;
27511 height = this.thumbEl.getHeight();
27512 this.baseScale = height / this.imageEl.OriginHeight;
27514 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27515 width = this.thumbEl.getWidth();
27516 this.baseScale = width / this.imageEl.OriginWidth;
27522 if(this.baseRotate == 6 || this.baseRotate == 8){
27524 width = this.thumbEl.getHeight();
27525 this.baseScale = width / this.imageEl.OriginHeight;
27527 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27528 height = this.thumbEl.getWidth();
27529 this.baseScale = height / this.imageEl.OriginHeight;
27532 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27533 height = this.thumbEl.getWidth();
27534 this.baseScale = height / this.imageEl.OriginHeight;
27536 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27537 width = this.thumbEl.getHeight();
27538 this.baseScale = width / this.imageEl.OriginWidth;
27545 width = this.thumbEl.getWidth();
27546 this.baseScale = width / this.imageEl.OriginWidth;
27548 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27549 height = this.thumbEl.getHeight();
27550 this.baseScale = height / this.imageEl.OriginHeight;
27553 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27555 height = this.thumbEl.getHeight();
27556 this.baseScale = height / this.imageEl.OriginHeight;
27558 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27559 width = this.thumbEl.getWidth();
27560 this.baseScale = width / this.imageEl.OriginWidth;
27568 getScaleLevel : function()
27570 return this.baseScale * Math.pow(1.1, this.scale);
27573 onTouchStart : function(e)
27575 if(!this.canvasLoaded){
27576 this.beforeSelectFile(e);
27580 var touches = e.browserEvent.touches;
27586 if(touches.length == 1){
27587 this.onMouseDown(e);
27591 if(touches.length != 2){
27597 for(var i = 0, finger; finger = touches[i]; i++){
27598 coords.push(finger.pageX, finger.pageY);
27601 var x = Math.pow(coords[0] - coords[2], 2);
27602 var y = Math.pow(coords[1] - coords[3], 2);
27604 this.startDistance = Math.sqrt(x + y);
27606 this.startScale = this.scale;
27608 this.pinching = true;
27609 this.dragable = false;
27613 onTouchMove : function(e)
27615 if(!this.pinching && !this.dragable){
27619 var touches = e.browserEvent.touches;
27626 this.onMouseMove(e);
27632 for(var i = 0, finger; finger = touches[i]; i++){
27633 coords.push(finger.pageX, finger.pageY);
27636 var x = Math.pow(coords[0] - coords[2], 2);
27637 var y = Math.pow(coords[1] - coords[3], 2);
27639 this.endDistance = Math.sqrt(x + y);
27641 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27643 if(!this.zoomable()){
27644 this.scale = this.startScale;
27652 onTouchEnd : function(e)
27654 this.pinching = false;
27655 this.dragable = false;
27659 process : function(file, crop)
27662 this.maskEl.mask(this.loadingText);
27665 this.xhr = new XMLHttpRequest();
27667 file.xhr = this.xhr;
27669 this.xhr.open(this.method, this.url, true);
27672 "Accept": "application/json",
27673 "Cache-Control": "no-cache",
27674 "X-Requested-With": "XMLHttpRequest"
27677 for (var headerName in headers) {
27678 var headerValue = headers[headerName];
27680 this.xhr.setRequestHeader(headerName, headerValue);
27686 this.xhr.onload = function()
27688 _this.xhrOnLoad(_this.xhr);
27691 this.xhr.onerror = function()
27693 _this.xhrOnError(_this.xhr);
27696 var formData = new FormData();
27698 formData.append('returnHTML', 'NO');
27701 formData.append('crop', crop);
27704 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27705 formData.append(this.paramName, file, file.name);
27708 if(typeof(file.filename) != 'undefined'){
27709 formData.append('filename', file.filename);
27712 if(typeof(file.mimetype) != 'undefined'){
27713 formData.append('mimetype', file.mimetype);
27716 if(this.fireEvent('arrange', this, formData) != false){
27717 this.xhr.send(formData);
27721 xhrOnLoad : function(xhr)
27724 this.maskEl.unmask();
27727 if (xhr.readyState !== 4) {
27728 this.fireEvent('exception', this, xhr);
27732 var response = Roo.decode(xhr.responseText);
27734 if(!response.success){
27735 this.fireEvent('exception', this, xhr);
27739 var response = Roo.decode(xhr.responseText);
27741 this.fireEvent('upload', this, response);
27745 xhrOnError : function()
27748 this.maskEl.unmask();
27751 Roo.log('xhr on error');
27753 var response = Roo.decode(xhr.responseText);
27759 prepare : function(file)
27762 this.maskEl.mask(this.loadingText);
27768 if(typeof(file) === 'string'){
27769 this.loadCanvas(file);
27773 if(!file || !this.urlAPI){
27778 this.cropType = file.type;
27782 if(this.fireEvent('prepare', this, this.file) != false){
27784 var reader = new FileReader();
27786 reader.onload = function (e) {
27787 if (e.target.error) {
27788 Roo.log(e.target.error);
27792 var buffer = e.target.result,
27793 dataView = new DataView(buffer),
27795 maxOffset = dataView.byteLength - 4,
27799 if (dataView.getUint16(0) === 0xffd8) {
27800 while (offset < maxOffset) {
27801 markerBytes = dataView.getUint16(offset);
27803 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27804 markerLength = dataView.getUint16(offset + 2) + 2;
27805 if (offset + markerLength > dataView.byteLength) {
27806 Roo.log('Invalid meta data: Invalid segment size.');
27810 if(markerBytes == 0xffe1){
27811 _this.parseExifData(
27818 offset += markerLength;
27828 var url = _this.urlAPI.createObjectURL(_this.file);
27830 _this.loadCanvas(url);
27835 reader.readAsArrayBuffer(this.file);
27841 parseExifData : function(dataView, offset, length)
27843 var tiffOffset = offset + 10,
27847 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27848 // No Exif data, might be XMP data instead
27852 // Check for the ASCII code for "Exif" (0x45786966):
27853 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27854 // No Exif data, might be XMP data instead
27857 if (tiffOffset + 8 > dataView.byteLength) {
27858 Roo.log('Invalid Exif data: Invalid segment size.');
27861 // Check for the two null bytes:
27862 if (dataView.getUint16(offset + 8) !== 0x0000) {
27863 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27866 // Check the byte alignment:
27867 switch (dataView.getUint16(tiffOffset)) {
27869 littleEndian = true;
27872 littleEndian = false;
27875 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27878 // Check for the TIFF tag marker (0x002A):
27879 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27880 Roo.log('Invalid Exif data: Missing TIFF marker.');
27883 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27884 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27886 this.parseExifTags(
27889 tiffOffset + dirOffset,
27894 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27899 if (dirOffset + 6 > dataView.byteLength) {
27900 Roo.log('Invalid Exif data: Invalid directory offset.');
27903 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27904 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27905 if (dirEndOffset + 4 > dataView.byteLength) {
27906 Roo.log('Invalid Exif data: Invalid directory size.');
27909 for (i = 0; i < tagsNumber; i += 1) {
27913 dirOffset + 2 + 12 * i, // tag offset
27917 // Return the offset to the next directory:
27918 return dataView.getUint32(dirEndOffset, littleEndian);
27921 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27923 var tag = dataView.getUint16(offset, littleEndian);
27925 this.exif[tag] = this.getExifValue(
27929 dataView.getUint16(offset + 2, littleEndian), // tag type
27930 dataView.getUint32(offset + 4, littleEndian), // tag length
27935 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27937 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27946 Roo.log('Invalid Exif data: Invalid tag type.');
27950 tagSize = tagType.size * length;
27951 // Determine if the value is contained in the dataOffset bytes,
27952 // or if the value at the dataOffset is a pointer to the actual data:
27953 dataOffset = tagSize > 4 ?
27954 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27955 if (dataOffset + tagSize > dataView.byteLength) {
27956 Roo.log('Invalid Exif data: Invalid data offset.');
27959 if (length === 1) {
27960 return tagType.getValue(dataView, dataOffset, littleEndian);
27963 for (i = 0; i < length; i += 1) {
27964 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27967 if (tagType.ascii) {
27969 // Concatenate the chars:
27970 for (i = 0; i < values.length; i += 1) {
27972 // Ignore the terminating NULL byte(s):
27973 if (c === '\u0000') {
27985 Roo.apply(Roo.bootstrap.UploadCropbox, {
27987 'Orientation': 0x0112
27991 1: 0, //'top-left',
27993 3: 180, //'bottom-right',
27994 // 4: 'bottom-left',
27996 6: 90, //'right-top',
27997 // 7: 'right-bottom',
27998 8: 270 //'left-bottom'
28002 // byte, 8-bit unsigned int:
28004 getValue: function (dataView, dataOffset) {
28005 return dataView.getUint8(dataOffset);
28009 // ascii, 8-bit byte:
28011 getValue: function (dataView, dataOffset) {
28012 return String.fromCharCode(dataView.getUint8(dataOffset));
28017 // short, 16 bit int:
28019 getValue: function (dataView, dataOffset, littleEndian) {
28020 return dataView.getUint16(dataOffset, littleEndian);
28024 // long, 32 bit int:
28026 getValue: function (dataView, dataOffset, littleEndian) {
28027 return dataView.getUint32(dataOffset, littleEndian);
28031 // rational = two long values, first is numerator, second is denominator:
28033 getValue: function (dataView, dataOffset, littleEndian) {
28034 return dataView.getUint32(dataOffset, littleEndian) /
28035 dataView.getUint32(dataOffset + 4, littleEndian);
28039 // slong, 32 bit signed int:
28041 getValue: function (dataView, dataOffset, littleEndian) {
28042 return dataView.getInt32(dataOffset, littleEndian);
28046 // srational, two slongs, first is numerator, second is denominator:
28048 getValue: function (dataView, dataOffset, littleEndian) {
28049 return dataView.getInt32(dataOffset, littleEndian) /
28050 dataView.getInt32(dataOffset + 4, littleEndian);
28060 cls : 'btn-group roo-upload-cropbox-rotate-left',
28061 action : 'rotate-left',
28065 cls : 'btn btn-default',
28066 html : '<i class="fa fa-undo"></i>'
28072 cls : 'btn-group roo-upload-cropbox-picture',
28073 action : 'picture',
28077 cls : 'btn btn-default',
28078 html : '<i class="fa fa-picture-o"></i>'
28084 cls : 'btn-group roo-upload-cropbox-rotate-right',
28085 action : 'rotate-right',
28089 cls : 'btn btn-default',
28090 html : '<i class="fa fa-repeat"></i>'
28098 cls : 'btn-group roo-upload-cropbox-rotate-left',
28099 action : 'rotate-left',
28103 cls : 'btn btn-default',
28104 html : '<i class="fa fa-undo"></i>'
28110 cls : 'btn-group roo-upload-cropbox-download',
28111 action : 'download',
28115 cls : 'btn btn-default',
28116 html : '<i class="fa fa-download"></i>'
28122 cls : 'btn-group roo-upload-cropbox-crop',
28127 cls : 'btn btn-default',
28128 html : '<i class="fa fa-crop"></i>'
28134 cls : 'btn-group roo-upload-cropbox-trash',
28139 cls : 'btn btn-default',
28140 html : '<i class="fa fa-trash"></i>'
28146 cls : 'btn-group roo-upload-cropbox-rotate-right',
28147 action : 'rotate-right',
28151 cls : 'btn btn-default',
28152 html : '<i class="fa fa-repeat"></i>'
28160 cls : 'btn-group roo-upload-cropbox-rotate-left',
28161 action : 'rotate-left',
28165 cls : 'btn btn-default',
28166 html : '<i class="fa fa-undo"></i>'
28172 cls : 'btn-group roo-upload-cropbox-rotate-right',
28173 action : 'rotate-right',
28177 cls : 'btn btn-default',
28178 html : '<i class="fa fa-repeat"></i>'
28191 * @class Roo.bootstrap.DocumentManager
28192 * @extends Roo.bootstrap.Component
28193 * Bootstrap DocumentManager class
28194 * @cfg {String} paramName default 'imageUpload'
28195 * @cfg {String} toolTipName default 'filename'
28196 * @cfg {String} method default POST
28197 * @cfg {String} url action url
28198 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28199 * @cfg {Boolean} multiple multiple upload default true
28200 * @cfg {Number} thumbSize default 300
28201 * @cfg {String} fieldLabel
28202 * @cfg {Number} labelWidth default 4
28203 * @cfg {String} labelAlign (left|top) default left
28204 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28205 * @cfg {Number} labellg set the width of label (1-12)
28206 * @cfg {Number} labelmd set the width of label (1-12)
28207 * @cfg {Number} labelsm set the width of label (1-12)
28208 * @cfg {Number} labelxs set the width of label (1-12)
28211 * Create a new DocumentManager
28212 * @param {Object} config The config object
28215 Roo.bootstrap.DocumentManager = function(config){
28216 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28219 this.delegates = [];
28224 * Fire when initial the DocumentManager
28225 * @param {Roo.bootstrap.DocumentManager} this
28230 * inspect selected file
28231 * @param {Roo.bootstrap.DocumentManager} this
28232 * @param {File} file
28237 * Fire when xhr load exception
28238 * @param {Roo.bootstrap.DocumentManager} this
28239 * @param {XMLHttpRequest} xhr
28241 "exception" : true,
28243 * @event afterupload
28244 * Fire when xhr load exception
28245 * @param {Roo.bootstrap.DocumentManager} this
28246 * @param {XMLHttpRequest} xhr
28248 "afterupload" : true,
28251 * prepare the form data
28252 * @param {Roo.bootstrap.DocumentManager} this
28253 * @param {Object} formData
28258 * Fire when remove the file
28259 * @param {Roo.bootstrap.DocumentManager} this
28260 * @param {Object} file
28265 * Fire after refresh the file
28266 * @param {Roo.bootstrap.DocumentManager} this
28271 * Fire after click the image
28272 * @param {Roo.bootstrap.DocumentManager} this
28273 * @param {Object} file
28278 * Fire when upload a image and editable set to true
28279 * @param {Roo.bootstrap.DocumentManager} this
28280 * @param {Object} file
28284 * @event beforeselectfile
28285 * Fire before select file
28286 * @param {Roo.bootstrap.DocumentManager} this
28288 "beforeselectfile" : true,
28291 * Fire before process file
28292 * @param {Roo.bootstrap.DocumentManager} this
28293 * @param {Object} file
28300 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28309 paramName : 'imageUpload',
28310 toolTipName : 'filename',
28313 labelAlign : 'left',
28323 getAutoCreate : function()
28325 var managerWidget = {
28327 cls : 'roo-document-manager',
28331 cls : 'roo-document-manager-selector',
28336 cls : 'roo-document-manager-uploader',
28340 cls : 'roo-document-manager-upload-btn',
28341 html : '<i class="fa fa-plus"></i>'
28352 cls : 'column col-md-12',
28357 if(this.fieldLabel.length){
28362 cls : 'column col-md-12',
28363 html : this.fieldLabel
28367 cls : 'column col-md-12',
28372 if(this.labelAlign == 'left'){
28377 html : this.fieldLabel
28386 if(this.labelWidth > 12){
28387 content[0].style = "width: " + this.labelWidth + 'px';
28390 if(this.labelWidth < 13 && this.labelmd == 0){
28391 this.labelmd = this.labelWidth;
28394 if(this.labellg > 0){
28395 content[0].cls += ' col-lg-' + this.labellg;
28396 content[1].cls += ' col-lg-' + (12 - this.labellg);
28399 if(this.labelmd > 0){
28400 content[0].cls += ' col-md-' + this.labelmd;
28401 content[1].cls += ' col-md-' + (12 - this.labelmd);
28404 if(this.labelsm > 0){
28405 content[0].cls += ' col-sm-' + this.labelsm;
28406 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28409 if(this.labelxs > 0){
28410 content[0].cls += ' col-xs-' + this.labelxs;
28411 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28419 cls : 'row clearfix',
28427 initEvents : function()
28429 this.managerEl = this.el.select('.roo-document-manager', true).first();
28430 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28432 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28433 this.selectorEl.hide();
28436 this.selectorEl.attr('multiple', 'multiple');
28439 this.selectorEl.on('change', this.onFileSelected, this);
28441 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28442 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28444 this.uploader.on('click', this.onUploaderClick, this);
28446 this.renderProgressDialog();
28450 window.addEventListener("resize", function() { _this.refresh(); } );
28452 this.fireEvent('initial', this);
28455 renderProgressDialog : function()
28459 this.progressDialog = new Roo.bootstrap.Modal({
28460 cls : 'roo-document-manager-progress-dialog',
28461 allow_close : false,
28471 btnclick : function() {
28472 _this.uploadCancel();
28478 this.progressDialog.render(Roo.get(document.body));
28480 this.progress = new Roo.bootstrap.Progress({
28481 cls : 'roo-document-manager-progress',
28486 this.progress.render(this.progressDialog.getChildContainer());
28488 this.progressBar = new Roo.bootstrap.ProgressBar({
28489 cls : 'roo-document-manager-progress-bar',
28492 aria_valuemax : 12,
28496 this.progressBar.render(this.progress.getChildContainer());
28499 onUploaderClick : function(e)
28501 e.preventDefault();
28503 if(this.fireEvent('beforeselectfile', this) != false){
28504 this.selectorEl.dom.click();
28509 onFileSelected : function(e)
28511 e.preventDefault();
28513 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28517 Roo.each(this.selectorEl.dom.files, function(file){
28518 if(this.fireEvent('inspect', this, file) != false){
28519 this.files.push(file);
28529 this.selectorEl.dom.value = '';
28531 if(!this.files.length){
28535 if(this.boxes > 0 && this.files.length > this.boxes){
28536 this.files = this.files.slice(0, this.boxes);
28539 this.uploader.show();
28541 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28542 this.uploader.hide();
28551 Roo.each(this.files, function(file){
28553 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28554 var f = this.renderPreview(file);
28559 if(file.type.indexOf('image') != -1){
28560 this.delegates.push(
28562 _this.process(file);
28563 }).createDelegate(this)
28571 _this.process(file);
28572 }).createDelegate(this)
28577 this.files = files;
28579 this.delegates = this.delegates.concat(docs);
28581 if(!this.delegates.length){
28586 this.progressBar.aria_valuemax = this.delegates.length;
28593 arrange : function()
28595 if(!this.delegates.length){
28596 this.progressDialog.hide();
28601 var delegate = this.delegates.shift();
28603 this.progressDialog.show();
28605 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28607 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28612 refresh : function()
28614 this.uploader.show();
28616 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28617 this.uploader.hide();
28620 Roo.isTouch ? this.closable(false) : this.closable(true);
28622 this.fireEvent('refresh', this);
28625 onRemove : function(e, el, o)
28627 e.preventDefault();
28629 this.fireEvent('remove', this, o);
28633 remove : function(o)
28637 Roo.each(this.files, function(file){
28638 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28647 this.files = files;
28654 Roo.each(this.files, function(file){
28659 file.target.remove();
28668 onClick : function(e, el, o)
28670 e.preventDefault();
28672 this.fireEvent('click', this, o);
28676 closable : function(closable)
28678 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28680 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28692 xhrOnLoad : function(xhr)
28694 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28698 if (xhr.readyState !== 4) {
28700 this.fireEvent('exception', this, xhr);
28704 var response = Roo.decode(xhr.responseText);
28706 if(!response.success){
28708 this.fireEvent('exception', this, xhr);
28712 var file = this.renderPreview(response.data);
28714 this.files.push(file);
28718 this.fireEvent('afterupload', this, xhr);
28722 xhrOnError : function(xhr)
28724 Roo.log('xhr on error');
28726 var response = Roo.decode(xhr.responseText);
28733 process : function(file)
28735 if(this.fireEvent('process', this, file) !== false){
28736 if(this.editable && file.type.indexOf('image') != -1){
28737 this.fireEvent('edit', this, file);
28741 this.uploadStart(file, false);
28748 uploadStart : function(file, crop)
28750 this.xhr = new XMLHttpRequest();
28752 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28757 file.xhr = this.xhr;
28759 this.managerEl.createChild({
28761 cls : 'roo-document-manager-loading',
28765 tooltip : file.name,
28766 cls : 'roo-document-manager-thumb',
28767 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28773 this.xhr.open(this.method, this.url, true);
28776 "Accept": "application/json",
28777 "Cache-Control": "no-cache",
28778 "X-Requested-With": "XMLHttpRequest"
28781 for (var headerName in headers) {
28782 var headerValue = headers[headerName];
28784 this.xhr.setRequestHeader(headerName, headerValue);
28790 this.xhr.onload = function()
28792 _this.xhrOnLoad(_this.xhr);
28795 this.xhr.onerror = function()
28797 _this.xhrOnError(_this.xhr);
28800 var formData = new FormData();
28802 formData.append('returnHTML', 'NO');
28805 formData.append('crop', crop);
28808 formData.append(this.paramName, file, file.name);
28815 if(this.fireEvent('prepare', this, formData, options) != false){
28817 if(options.manually){
28821 this.xhr.send(formData);
28825 this.uploadCancel();
28828 uploadCancel : function()
28834 this.delegates = [];
28836 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28843 renderPreview : function(file)
28845 if(typeof(file.target) != 'undefined' && file.target){
28849 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
28851 var previewEl = this.managerEl.createChild({
28853 cls : 'roo-document-manager-preview',
28857 tooltip : file[this.toolTipName],
28858 cls : 'roo-document-manager-thumb',
28859 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
28864 html : '<i class="fa fa-times-circle"></i>'
28869 var close = previewEl.select('button.close', true).first();
28871 close.on('click', this.onRemove, this, file);
28873 file.target = previewEl;
28875 var image = previewEl.select('img', true).first();
28879 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28881 image.on('click', this.onClick, this, file);
28887 onPreviewLoad : function(file, image)
28889 if(typeof(file.target) == 'undefined' || !file.target){
28893 var width = image.dom.naturalWidth || image.dom.width;
28894 var height = image.dom.naturalHeight || image.dom.height;
28896 if(width > height){
28897 file.target.addClass('wide');
28901 file.target.addClass('tall');
28906 uploadFromSource : function(file, crop)
28908 this.xhr = new XMLHttpRequest();
28910 this.managerEl.createChild({
28912 cls : 'roo-document-manager-loading',
28916 tooltip : file.name,
28917 cls : 'roo-document-manager-thumb',
28918 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28924 this.xhr.open(this.method, this.url, true);
28927 "Accept": "application/json",
28928 "Cache-Control": "no-cache",
28929 "X-Requested-With": "XMLHttpRequest"
28932 for (var headerName in headers) {
28933 var headerValue = headers[headerName];
28935 this.xhr.setRequestHeader(headerName, headerValue);
28941 this.xhr.onload = function()
28943 _this.xhrOnLoad(_this.xhr);
28946 this.xhr.onerror = function()
28948 _this.xhrOnError(_this.xhr);
28951 var formData = new FormData();
28953 formData.append('returnHTML', 'NO');
28955 formData.append('crop', crop);
28957 if(typeof(file.filename) != 'undefined'){
28958 formData.append('filename', file.filename);
28961 if(typeof(file.mimetype) != 'undefined'){
28962 formData.append('mimetype', file.mimetype);
28967 if(this.fireEvent('prepare', this, formData) != false){
28968 this.xhr.send(formData);
28978 * @class Roo.bootstrap.DocumentViewer
28979 * @extends Roo.bootstrap.Component
28980 * Bootstrap DocumentViewer class
28981 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28982 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28985 * Create a new DocumentViewer
28986 * @param {Object} config The config object
28989 Roo.bootstrap.DocumentViewer = function(config){
28990 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28995 * Fire after initEvent
28996 * @param {Roo.bootstrap.DocumentViewer} this
29002 * @param {Roo.bootstrap.DocumentViewer} this
29007 * Fire after download button
29008 * @param {Roo.bootstrap.DocumentViewer} this
29013 * Fire after trash button
29014 * @param {Roo.bootstrap.DocumentViewer} this
29021 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29023 showDownload : true,
29027 getAutoCreate : function()
29031 cls : 'roo-document-viewer',
29035 cls : 'roo-document-viewer-body',
29039 cls : 'roo-document-viewer-thumb',
29043 cls : 'roo-document-viewer-image'
29051 cls : 'roo-document-viewer-footer',
29054 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29058 cls : 'btn-group roo-document-viewer-download',
29062 cls : 'btn btn-default',
29063 html : '<i class="fa fa-download"></i>'
29069 cls : 'btn-group roo-document-viewer-trash',
29073 cls : 'btn btn-default',
29074 html : '<i class="fa fa-trash"></i>'
29087 initEvents : function()
29089 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29090 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29092 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29093 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29095 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29096 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29098 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29099 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29101 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29102 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29104 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29105 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29107 this.bodyEl.on('click', this.onClick, this);
29108 this.downloadBtn.on('click', this.onDownload, this);
29109 this.trashBtn.on('click', this.onTrash, this);
29111 this.downloadBtn.hide();
29112 this.trashBtn.hide();
29114 if(this.showDownload){
29115 this.downloadBtn.show();
29118 if(this.showTrash){
29119 this.trashBtn.show();
29122 if(!this.showDownload && !this.showTrash) {
29123 this.footerEl.hide();
29128 initial : function()
29130 this.fireEvent('initial', this);
29134 onClick : function(e)
29136 e.preventDefault();
29138 this.fireEvent('click', this);
29141 onDownload : function(e)
29143 e.preventDefault();
29145 this.fireEvent('download', this);
29148 onTrash : function(e)
29150 e.preventDefault();
29152 this.fireEvent('trash', this);
29164 * @class Roo.bootstrap.NavProgressBar
29165 * @extends Roo.bootstrap.Component
29166 * Bootstrap NavProgressBar class
29169 * Create a new nav progress bar
29170 * @param {Object} config The config object
29173 Roo.bootstrap.NavProgressBar = function(config){
29174 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29176 this.bullets = this.bullets || [];
29178 // Roo.bootstrap.NavProgressBar.register(this);
29182 * Fires when the active item changes
29183 * @param {Roo.bootstrap.NavProgressBar} this
29184 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29185 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29192 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29197 getAutoCreate : function()
29199 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29203 cls : 'roo-navigation-bar-group',
29207 cls : 'roo-navigation-top-bar'
29211 cls : 'roo-navigation-bullets-bar',
29215 cls : 'roo-navigation-bar'
29222 cls : 'roo-navigation-bottom-bar'
29232 initEvents: function()
29237 onRender : function(ct, position)
29239 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29241 if(this.bullets.length){
29242 Roo.each(this.bullets, function(b){
29251 addItem : function(cfg)
29253 var item = new Roo.bootstrap.NavProgressItem(cfg);
29255 item.parentId = this.id;
29256 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29259 var top = new Roo.bootstrap.Element({
29261 cls : 'roo-navigation-bar-text'
29264 var bottom = new Roo.bootstrap.Element({
29266 cls : 'roo-navigation-bar-text'
29269 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29270 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29272 var topText = new Roo.bootstrap.Element({
29274 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29277 var bottomText = new Roo.bootstrap.Element({
29279 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29282 topText.onRender(top.el, null);
29283 bottomText.onRender(bottom.el, null);
29286 item.bottomEl = bottom;
29289 this.barItems.push(item);
29294 getActive : function()
29296 var active = false;
29298 Roo.each(this.barItems, function(v){
29300 if (!v.isActive()) {
29312 setActiveItem : function(item)
29316 Roo.each(this.barItems, function(v){
29317 if (v.rid == item.rid) {
29321 if (v.isActive()) {
29322 v.setActive(false);
29327 item.setActive(true);
29329 this.fireEvent('changed', this, item, prev);
29332 getBarItem: function(rid)
29336 Roo.each(this.barItems, function(e) {
29337 if (e.rid != rid) {
29348 indexOfItem : function(item)
29352 Roo.each(this.barItems, function(v, i){
29354 if (v.rid != item.rid) {
29365 setActiveNext : function()
29367 var i = this.indexOfItem(this.getActive());
29369 if (i > this.barItems.length) {
29373 this.setActiveItem(this.barItems[i+1]);
29376 setActivePrev : function()
29378 var i = this.indexOfItem(this.getActive());
29384 this.setActiveItem(this.barItems[i-1]);
29387 format : function()
29389 if(!this.barItems.length){
29393 var width = 100 / this.barItems.length;
29395 Roo.each(this.barItems, function(i){
29396 i.el.setStyle('width', width + '%');
29397 i.topEl.el.setStyle('width', width + '%');
29398 i.bottomEl.el.setStyle('width', width + '%');
29407 * Nav Progress Item
29412 * @class Roo.bootstrap.NavProgressItem
29413 * @extends Roo.bootstrap.Component
29414 * Bootstrap NavProgressItem class
29415 * @cfg {String} rid the reference id
29416 * @cfg {Boolean} active (true|false) Is item active default false
29417 * @cfg {Boolean} disabled (true|false) Is item active default false
29418 * @cfg {String} html
29419 * @cfg {String} position (top|bottom) text position default bottom
29420 * @cfg {String} icon show icon instead of number
29423 * Create a new NavProgressItem
29424 * @param {Object} config The config object
29426 Roo.bootstrap.NavProgressItem = function(config){
29427 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29432 * The raw click event for the entire grid.
29433 * @param {Roo.bootstrap.NavProgressItem} this
29434 * @param {Roo.EventObject} e
29441 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29447 position : 'bottom',
29450 getAutoCreate : function()
29452 var iconCls = 'roo-navigation-bar-item-icon';
29454 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29458 cls: 'roo-navigation-bar-item',
29468 cfg.cls += ' active';
29471 cfg.cls += ' disabled';
29477 disable : function()
29479 this.setDisabled(true);
29482 enable : function()
29484 this.setDisabled(false);
29487 initEvents: function()
29489 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29491 this.iconEl.on('click', this.onClick, this);
29494 onClick : function(e)
29496 e.preventDefault();
29502 if(this.fireEvent('click', this, e) === false){
29506 this.parent().setActiveItem(this);
29509 isActive: function ()
29511 return this.active;
29514 setActive : function(state)
29516 if(this.active == state){
29520 this.active = state;
29523 this.el.addClass('active');
29527 this.el.removeClass('active');
29532 setDisabled : function(state)
29534 if(this.disabled == state){
29538 this.disabled = state;
29541 this.el.addClass('disabled');
29545 this.el.removeClass('disabled');
29548 tooltipEl : function()
29550 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29563 * @class Roo.bootstrap.FieldLabel
29564 * @extends Roo.bootstrap.Component
29565 * Bootstrap FieldLabel class
29566 * @cfg {String} html contents of the element
29567 * @cfg {String} tag tag of the element default label
29568 * @cfg {String} cls class of the element
29569 * @cfg {String} target label target
29570 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29571 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29572 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29573 * @cfg {String} iconTooltip default "This field is required"
29576 * Create a new FieldLabel
29577 * @param {Object} config The config object
29580 Roo.bootstrap.FieldLabel = function(config){
29581 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29586 * Fires after the field has been marked as invalid.
29587 * @param {Roo.form.FieldLabel} this
29588 * @param {String} msg The validation message
29593 * Fires after the field has been validated with no errors.
29594 * @param {Roo.form.FieldLabel} this
29600 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29607 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29608 validClass : 'text-success fa fa-lg fa-check',
29609 iconTooltip : 'This field is required',
29611 getAutoCreate : function(){
29615 cls : 'roo-bootstrap-field-label ' + this.cls,
29621 tooltip : this.iconTooltip
29633 initEvents: function()
29635 Roo.bootstrap.Element.superclass.initEvents.call(this);
29637 this.iconEl = this.el.select('i', true).first();
29639 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29641 Roo.bootstrap.FieldLabel.register(this);
29645 * Mark this field as valid
29647 markValid : function()
29649 this.iconEl.show();
29651 this.iconEl.removeClass(this.invalidClass);
29653 this.iconEl.addClass(this.validClass);
29655 this.fireEvent('valid', this);
29659 * Mark this field as invalid
29660 * @param {String} msg The validation message
29662 markInvalid : function(msg)
29664 this.iconEl.show();
29666 this.iconEl.removeClass(this.validClass);
29668 this.iconEl.addClass(this.invalidClass);
29670 this.fireEvent('invalid', this, msg);
29676 Roo.apply(Roo.bootstrap.FieldLabel, {
29681 * register a FieldLabel Group
29682 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29684 register : function(label)
29686 if(this.groups.hasOwnProperty(label.target)){
29690 this.groups[label.target] = label;
29694 * fetch a FieldLabel Group based on the target
29695 * @param {string} target
29696 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29698 get: function(target) {
29699 if (typeof(this.groups[target]) == 'undefined') {
29703 return this.groups[target] ;
29712 * page DateSplitField.
29718 * @class Roo.bootstrap.DateSplitField
29719 * @extends Roo.bootstrap.Component
29720 * Bootstrap DateSplitField class
29721 * @cfg {string} fieldLabel - the label associated
29722 * @cfg {Number} labelWidth set the width of label (0-12)
29723 * @cfg {String} labelAlign (top|left)
29724 * @cfg {Boolean} dayAllowBlank (true|false) default false
29725 * @cfg {Boolean} monthAllowBlank (true|false) default false
29726 * @cfg {Boolean} yearAllowBlank (true|false) default false
29727 * @cfg {string} dayPlaceholder
29728 * @cfg {string} monthPlaceholder
29729 * @cfg {string} yearPlaceholder
29730 * @cfg {string} dayFormat default 'd'
29731 * @cfg {string} monthFormat default 'm'
29732 * @cfg {string} yearFormat default 'Y'
29733 * @cfg {Number} labellg set the width of label (1-12)
29734 * @cfg {Number} labelmd set the width of label (1-12)
29735 * @cfg {Number} labelsm set the width of label (1-12)
29736 * @cfg {Number} labelxs set the width of label (1-12)
29740 * Create a new DateSplitField
29741 * @param {Object} config The config object
29744 Roo.bootstrap.DateSplitField = function(config){
29745 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29751 * getting the data of years
29752 * @param {Roo.bootstrap.DateSplitField} this
29753 * @param {Object} years
29758 * getting the data of days
29759 * @param {Roo.bootstrap.DateSplitField} this
29760 * @param {Object} days
29765 * Fires after the field has been marked as invalid.
29766 * @param {Roo.form.Field} this
29767 * @param {String} msg The validation message
29772 * Fires after the field has been validated with no errors.
29773 * @param {Roo.form.Field} this
29779 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29782 labelAlign : 'top',
29784 dayAllowBlank : false,
29785 monthAllowBlank : false,
29786 yearAllowBlank : false,
29787 dayPlaceholder : '',
29788 monthPlaceholder : '',
29789 yearPlaceholder : '',
29793 isFormField : true,
29799 getAutoCreate : function()
29803 cls : 'row roo-date-split-field-group',
29808 cls : 'form-hidden-field roo-date-split-field-group-value',
29814 var labelCls = 'col-md-12';
29815 var contentCls = 'col-md-4';
29817 if(this.fieldLabel){
29821 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29825 html : this.fieldLabel
29830 if(this.labelAlign == 'left'){
29832 if(this.labelWidth > 12){
29833 label.style = "width: " + this.labelWidth + 'px';
29836 if(this.labelWidth < 13 && this.labelmd == 0){
29837 this.labelmd = this.labelWidth;
29840 if(this.labellg > 0){
29841 labelCls = ' col-lg-' + this.labellg;
29842 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29845 if(this.labelmd > 0){
29846 labelCls = ' col-md-' + this.labelmd;
29847 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29850 if(this.labelsm > 0){
29851 labelCls = ' col-sm-' + this.labelsm;
29852 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29855 if(this.labelxs > 0){
29856 labelCls = ' col-xs-' + this.labelxs;
29857 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29861 label.cls += ' ' + labelCls;
29863 cfg.cn.push(label);
29866 Roo.each(['day', 'month', 'year'], function(t){
29869 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29876 inputEl: function ()
29878 return this.el.select('.roo-date-split-field-group-value', true).first();
29881 onRender : function(ct, position)
29885 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29887 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29889 this.dayField = new Roo.bootstrap.ComboBox({
29890 allowBlank : this.dayAllowBlank,
29891 alwaysQuery : true,
29892 displayField : 'value',
29895 forceSelection : true,
29897 placeholder : this.dayPlaceholder,
29898 selectOnFocus : true,
29899 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29900 triggerAction : 'all',
29902 valueField : 'value',
29903 store : new Roo.data.SimpleStore({
29904 data : (function() {
29906 _this.fireEvent('days', _this, days);
29909 fields : [ 'value' ]
29912 select : function (_self, record, index)
29914 _this.setValue(_this.getValue());
29919 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29921 this.monthField = new Roo.bootstrap.MonthField({
29922 after : '<i class=\"fa fa-calendar\"></i>',
29923 allowBlank : this.monthAllowBlank,
29924 placeholder : this.monthPlaceholder,
29927 render : function (_self)
29929 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29930 e.preventDefault();
29934 select : function (_self, oldvalue, newvalue)
29936 _this.setValue(_this.getValue());
29941 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29943 this.yearField = new Roo.bootstrap.ComboBox({
29944 allowBlank : this.yearAllowBlank,
29945 alwaysQuery : true,
29946 displayField : 'value',
29949 forceSelection : true,
29951 placeholder : this.yearPlaceholder,
29952 selectOnFocus : true,
29953 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29954 triggerAction : 'all',
29956 valueField : 'value',
29957 store : new Roo.data.SimpleStore({
29958 data : (function() {
29960 _this.fireEvent('years', _this, years);
29963 fields : [ 'value' ]
29966 select : function (_self, record, index)
29968 _this.setValue(_this.getValue());
29973 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29976 setValue : function(v, format)
29978 this.inputEl.dom.value = v;
29980 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29982 var d = Date.parseDate(v, f);
29989 this.setDay(d.format(this.dayFormat));
29990 this.setMonth(d.format(this.monthFormat));
29991 this.setYear(d.format(this.yearFormat));
29998 setDay : function(v)
30000 this.dayField.setValue(v);
30001 this.inputEl.dom.value = this.getValue();
30006 setMonth : function(v)
30008 this.monthField.setValue(v, true);
30009 this.inputEl.dom.value = this.getValue();
30014 setYear : function(v)
30016 this.yearField.setValue(v);
30017 this.inputEl.dom.value = this.getValue();
30022 getDay : function()
30024 return this.dayField.getValue();
30027 getMonth : function()
30029 return this.monthField.getValue();
30032 getYear : function()
30034 return this.yearField.getValue();
30037 getValue : function()
30039 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30041 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30051 this.inputEl.dom.value = '';
30056 validate : function()
30058 var d = this.dayField.validate();
30059 var m = this.monthField.validate();
30060 var y = this.yearField.validate();
30065 (!this.dayAllowBlank && !d) ||
30066 (!this.monthAllowBlank && !m) ||
30067 (!this.yearAllowBlank && !y)
30072 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30081 this.markInvalid();
30086 markValid : function()
30089 var label = this.el.select('label', true).first();
30090 var icon = this.el.select('i.fa-star', true).first();
30096 this.fireEvent('valid', this);
30100 * Mark this field as invalid
30101 * @param {String} msg The validation message
30103 markInvalid : function(msg)
30106 var label = this.el.select('label', true).first();
30107 var icon = this.el.select('i.fa-star', true).first();
30109 if(label && !icon){
30110 this.el.select('.roo-date-split-field-label', true).createChild({
30112 cls : 'text-danger fa fa-lg fa-star',
30113 tooltip : 'This field is required',
30114 style : 'margin-right:5px;'
30118 this.fireEvent('invalid', this, msg);
30121 clearInvalid : function()
30123 var label = this.el.select('label', true).first();
30124 var icon = this.el.select('i.fa-star', true).first();
30130 this.fireEvent('valid', this);
30133 getName: function()
30143 * http://masonry.desandro.com
30145 * The idea is to render all the bricks based on vertical width...
30147 * The original code extends 'outlayer' - we might need to use that....
30153 * @class Roo.bootstrap.LayoutMasonry
30154 * @extends Roo.bootstrap.Component
30155 * Bootstrap Layout Masonry class
30158 * Create a new Element
30159 * @param {Object} config The config object
30162 Roo.bootstrap.LayoutMasonry = function(config){
30164 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30168 Roo.bootstrap.LayoutMasonry.register(this);
30174 * Fire after layout the items
30175 * @param {Roo.bootstrap.LayoutMasonry} this
30176 * @param {Roo.EventObject} e
30183 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30186 * @cfg {Boolean} isLayoutInstant = no animation?
30188 isLayoutInstant : false, // needed?
30191 * @cfg {Number} boxWidth width of the columns
30196 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30201 * @cfg {Number} padWidth padding below box..
30206 * @cfg {Number} gutter gutter width..
30211 * @cfg {Number} maxCols maximum number of columns
30217 * @cfg {Boolean} isAutoInitial defalut true
30219 isAutoInitial : true,
30224 * @cfg {Boolean} isHorizontal defalut false
30226 isHorizontal : false,
30228 currentSize : null,
30234 bricks: null, //CompositeElement
30238 _isLayoutInited : false,
30240 // isAlternative : false, // only use for vertical layout...
30243 * @cfg {Number} alternativePadWidth padding below box..
30245 alternativePadWidth : 50,
30247 selectedBrick : [],
30249 getAutoCreate : function(){
30251 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30255 cls: 'blog-masonary-wrapper ' + this.cls,
30257 cls : 'mas-boxes masonary'
30264 getChildContainer: function( )
30266 if (this.boxesEl) {
30267 return this.boxesEl;
30270 this.boxesEl = this.el.select('.mas-boxes').first();
30272 return this.boxesEl;
30276 initEvents : function()
30280 if(this.isAutoInitial){
30281 Roo.log('hook children rendered');
30282 this.on('childrenrendered', function() {
30283 Roo.log('children rendered');
30289 initial : function()
30291 this.selectedBrick = [];
30293 this.currentSize = this.el.getBox(true);
30295 Roo.EventManager.onWindowResize(this.resize, this);
30297 if(!this.isAutoInitial){
30305 //this.layout.defer(500,this);
30309 resize : function()
30311 var cs = this.el.getBox(true);
30314 this.currentSize.width == cs.width &&
30315 this.currentSize.x == cs.x &&
30316 this.currentSize.height == cs.height &&
30317 this.currentSize.y == cs.y
30319 Roo.log("no change in with or X or Y");
30323 this.currentSize = cs;
30329 layout : function()
30331 this._resetLayout();
30333 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30335 this.layoutItems( isInstant );
30337 this._isLayoutInited = true;
30339 this.fireEvent('layout', this);
30343 _resetLayout : function()
30345 if(this.isHorizontal){
30346 this.horizontalMeasureColumns();
30350 this.verticalMeasureColumns();
30354 verticalMeasureColumns : function()
30356 this.getContainerWidth();
30358 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30359 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30363 var boxWidth = this.boxWidth + this.padWidth;
30365 if(this.containerWidth < this.boxWidth){
30366 boxWidth = this.containerWidth
30369 var containerWidth = this.containerWidth;
30371 var cols = Math.floor(containerWidth / boxWidth);
30373 this.cols = Math.max( cols, 1 );
30375 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30377 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30379 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30381 this.colWidth = boxWidth + avail - this.padWidth;
30383 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30384 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30387 horizontalMeasureColumns : function()
30389 this.getContainerWidth();
30391 var boxWidth = this.boxWidth;
30393 if(this.containerWidth < boxWidth){
30394 boxWidth = this.containerWidth;
30397 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30399 this.el.setHeight(boxWidth);
30403 getContainerWidth : function()
30405 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30408 layoutItems : function( isInstant )
30410 Roo.log(this.bricks);
30412 var items = Roo.apply([], this.bricks);
30414 if(this.isHorizontal){
30415 this._horizontalLayoutItems( items , isInstant );
30419 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30420 // this._verticalAlternativeLayoutItems( items , isInstant );
30424 this._verticalLayoutItems( items , isInstant );
30428 _verticalLayoutItems : function ( items , isInstant)
30430 if ( !items || !items.length ) {
30435 ['xs', 'xs', 'xs', 'tall'],
30436 ['xs', 'xs', 'tall'],
30437 ['xs', 'xs', 'sm'],
30438 ['xs', 'xs', 'xs'],
30444 ['sm', 'xs', 'xs'],
30448 ['tall', 'xs', 'xs', 'xs'],
30449 ['tall', 'xs', 'xs'],
30461 Roo.each(items, function(item, k){
30463 switch (item.size) {
30464 // these layouts take up a full box,
30475 boxes.push([item]);
30498 var filterPattern = function(box, length)
30506 var pattern = box.slice(0, length);
30510 Roo.each(pattern, function(i){
30511 format.push(i.size);
30514 Roo.each(standard, function(s){
30516 if(String(s) != String(format)){
30525 if(!match && length == 1){
30530 filterPattern(box, length - 1);
30534 queue.push(pattern);
30536 box = box.slice(length, box.length);
30538 filterPattern(box, 4);
30544 Roo.each(boxes, function(box, k){
30550 if(box.length == 1){
30555 filterPattern(box, 4);
30559 this._processVerticalLayoutQueue( queue, isInstant );
30563 // _verticalAlternativeLayoutItems : function( items , isInstant )
30565 // if ( !items || !items.length ) {
30569 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30573 _horizontalLayoutItems : function ( items , isInstant)
30575 if ( !items || !items.length || items.length < 3) {
30581 var eItems = items.slice(0, 3);
30583 items = items.slice(3, items.length);
30586 ['xs', 'xs', 'xs', 'wide'],
30587 ['xs', 'xs', 'wide'],
30588 ['xs', 'xs', 'sm'],
30589 ['xs', 'xs', 'xs'],
30595 ['sm', 'xs', 'xs'],
30599 ['wide', 'xs', 'xs', 'xs'],
30600 ['wide', 'xs', 'xs'],
30613 Roo.each(items, function(item, k){
30615 switch (item.size) {
30626 boxes.push([item]);
30650 var filterPattern = function(box, length)
30658 var pattern = box.slice(0, length);
30662 Roo.each(pattern, function(i){
30663 format.push(i.size);
30666 Roo.each(standard, function(s){
30668 if(String(s) != String(format)){
30677 if(!match && length == 1){
30682 filterPattern(box, length - 1);
30686 queue.push(pattern);
30688 box = box.slice(length, box.length);
30690 filterPattern(box, 4);
30696 Roo.each(boxes, function(box, k){
30702 if(box.length == 1){
30707 filterPattern(box, 4);
30714 var pos = this.el.getBox(true);
30718 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30720 var hit_end = false;
30722 Roo.each(queue, function(box){
30726 Roo.each(box, function(b){
30728 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30738 Roo.each(box, function(b){
30740 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30743 mx = Math.max(mx, b.x);
30747 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30751 Roo.each(box, function(b){
30753 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30767 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30770 /** Sets position of item in DOM
30771 * @param {Element} item
30772 * @param {Number} x - horizontal position
30773 * @param {Number} y - vertical position
30774 * @param {Boolean} isInstant - disables transitions
30776 _processVerticalLayoutQueue : function( queue, isInstant )
30778 var pos = this.el.getBox(true);
30783 for (var i = 0; i < this.cols; i++){
30787 Roo.each(queue, function(box, k){
30789 var col = k % this.cols;
30791 Roo.each(box, function(b,kk){
30793 b.el.position('absolute');
30795 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30796 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30798 if(b.size == 'md-left' || b.size == 'md-right'){
30799 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30800 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30803 b.el.setWidth(width);
30804 b.el.setHeight(height);
30806 b.el.select('iframe',true).setSize(width,height);
30810 for (var i = 0; i < this.cols; i++){
30812 if(maxY[i] < maxY[col]){
30817 col = Math.min(col, i);
30821 x = pos.x + col * (this.colWidth + this.padWidth);
30825 var positions = [];
30827 switch (box.length){
30829 positions = this.getVerticalOneBoxColPositions(x, y, box);
30832 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30835 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30838 positions = this.getVerticalFourBoxColPositions(x, y, box);
30844 Roo.each(box, function(b,kk){
30846 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30848 var sz = b.el.getSize();
30850 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30858 for (var i = 0; i < this.cols; i++){
30859 mY = Math.max(mY, maxY[i]);
30862 this.el.setHeight(mY - pos.y);
30866 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30868 // var pos = this.el.getBox(true);
30871 // var maxX = pos.right;
30873 // var maxHeight = 0;
30875 // Roo.each(items, function(item, k){
30879 // item.el.position('absolute');
30881 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30883 // item.el.setWidth(width);
30885 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30887 // item.el.setHeight(height);
30890 // item.el.setXY([x, y], isInstant ? false : true);
30892 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30895 // y = y + height + this.alternativePadWidth;
30897 // maxHeight = maxHeight + height + this.alternativePadWidth;
30901 // this.el.setHeight(maxHeight);
30905 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30907 var pos = this.el.getBox(true);
30912 var maxX = pos.right;
30914 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30916 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30918 Roo.each(queue, function(box, k){
30920 Roo.each(box, function(b, kk){
30922 b.el.position('absolute');
30924 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30925 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30927 if(b.size == 'md-left' || b.size == 'md-right'){
30928 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30929 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30932 b.el.setWidth(width);
30933 b.el.setHeight(height);
30941 var positions = [];
30943 switch (box.length){
30945 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30948 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30951 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30954 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30960 Roo.each(box, function(b,kk){
30962 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30964 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30972 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30974 Roo.each(eItems, function(b,k){
30976 b.size = (k == 0) ? 'sm' : 'xs';
30977 b.x = (k == 0) ? 2 : 1;
30978 b.y = (k == 0) ? 2 : 1;
30980 b.el.position('absolute');
30982 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30984 b.el.setWidth(width);
30986 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30988 b.el.setHeight(height);
30992 var positions = [];
30995 x : maxX - this.unitWidth * 2 - this.gutter,
31000 x : maxX - this.unitWidth,
31001 y : minY + (this.unitWidth + this.gutter) * 2
31005 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31009 Roo.each(eItems, function(b,k){
31011 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31017 getVerticalOneBoxColPositions : function(x, y, box)
31021 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31023 if(box[0].size == 'md-left'){
31027 if(box[0].size == 'md-right'){
31032 x : x + (this.unitWidth + this.gutter) * rand,
31039 getVerticalTwoBoxColPositions : function(x, y, box)
31043 if(box[0].size == 'xs'){
31047 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31051 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31065 x : x + (this.unitWidth + this.gutter) * 2,
31066 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31073 getVerticalThreeBoxColPositions : function(x, y, box)
31077 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31085 x : x + (this.unitWidth + this.gutter) * 1,
31090 x : x + (this.unitWidth + this.gutter) * 2,
31098 if(box[0].size == 'xs' && box[1].size == 'xs'){
31107 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31111 x : x + (this.unitWidth + this.gutter) * 1,
31125 x : x + (this.unitWidth + this.gutter) * 2,
31130 x : x + (this.unitWidth + this.gutter) * 2,
31131 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31138 getVerticalFourBoxColPositions : function(x, y, box)
31142 if(box[0].size == 'xs'){
31151 y : y + (this.unitHeight + this.gutter) * 1
31156 y : y + (this.unitHeight + this.gutter) * 2
31160 x : x + (this.unitWidth + this.gutter) * 1,
31174 x : x + (this.unitWidth + this.gutter) * 2,
31179 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31180 y : y + (this.unitHeight + this.gutter) * 1
31184 x : x + (this.unitWidth + this.gutter) * 2,
31185 y : y + (this.unitWidth + this.gutter) * 2
31192 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31196 if(box[0].size == 'md-left'){
31198 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31205 if(box[0].size == 'md-right'){
31207 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31208 y : minY + (this.unitWidth + this.gutter) * 1
31214 var rand = Math.floor(Math.random() * (4 - box[0].y));
31217 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31218 y : minY + (this.unitWidth + this.gutter) * rand
31225 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31229 if(box[0].size == 'xs'){
31232 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31237 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31238 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31246 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31251 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31252 y : minY + (this.unitWidth + this.gutter) * 2
31259 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31263 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31266 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31271 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31272 y : minY + (this.unitWidth + this.gutter) * 1
31276 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31277 y : minY + (this.unitWidth + this.gutter) * 2
31284 if(box[0].size == 'xs' && box[1].size == 'xs'){
31287 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31292 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31297 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31298 y : minY + (this.unitWidth + this.gutter) * 1
31306 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31311 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31312 y : minY + (this.unitWidth + this.gutter) * 2
31316 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31317 y : minY + (this.unitWidth + this.gutter) * 2
31324 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31328 if(box[0].size == 'xs'){
31331 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31336 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31341 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),
31346 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31347 y : minY + (this.unitWidth + this.gutter) * 1
31355 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31360 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31361 y : minY + (this.unitWidth + this.gutter) * 2
31365 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31366 y : minY + (this.unitWidth + this.gutter) * 2
31370 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),
31371 y : minY + (this.unitWidth + this.gutter) * 2
31379 * remove a Masonry Brick
31380 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31382 removeBrick : function(brick_id)
31388 for (var i = 0; i<this.bricks.length; i++) {
31389 if (this.bricks[i].id == brick_id) {
31390 this.bricks.splice(i,1);
31391 this.el.dom.removeChild(Roo.get(brick_id).dom);
31398 * adds a Masonry Brick
31399 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31401 addBrick : function(cfg)
31403 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31404 //this.register(cn);
31405 cn.parentId = this.id;
31406 cn.onRender(this.el, null);
31411 * register a Masonry Brick
31412 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31415 register : function(brick)
31417 this.bricks.push(brick);
31418 brick.masonryId = this.id;
31422 * clear all the Masonry Brick
31424 clearAll : function()
31427 //this.getChildContainer().dom.innerHTML = "";
31428 this.el.dom.innerHTML = '';
31431 getSelected : function()
31433 if (!this.selectedBrick) {
31437 return this.selectedBrick;
31441 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31445 * register a Masonry Layout
31446 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31449 register : function(layout)
31451 this.groups[layout.id] = layout;
31454 * fetch a Masonry Layout based on the masonry layout ID
31455 * @param {string} the masonry layout to add
31456 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31459 get: function(layout_id) {
31460 if (typeof(this.groups[layout_id]) == 'undefined') {
31463 return this.groups[layout_id] ;
31475 * http://masonry.desandro.com
31477 * The idea is to render all the bricks based on vertical width...
31479 * The original code extends 'outlayer' - we might need to use that....
31485 * @class Roo.bootstrap.LayoutMasonryAuto
31486 * @extends Roo.bootstrap.Component
31487 * Bootstrap Layout Masonry class
31490 * Create a new Element
31491 * @param {Object} config The config object
31494 Roo.bootstrap.LayoutMasonryAuto = function(config){
31495 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31498 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31501 * @cfg {Boolean} isFitWidth - resize the width..
31503 isFitWidth : false, // options..
31505 * @cfg {Boolean} isOriginLeft = left align?
31507 isOriginLeft : true,
31509 * @cfg {Boolean} isOriginTop = top align?
31511 isOriginTop : false,
31513 * @cfg {Boolean} isLayoutInstant = no animation?
31515 isLayoutInstant : false, // needed?
31517 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31519 isResizingContainer : true,
31521 * @cfg {Number} columnWidth width of the columns
31527 * @cfg {Number} maxCols maximum number of columns
31532 * @cfg {Number} padHeight padding below box..
31538 * @cfg {Boolean} isAutoInitial defalut true
31541 isAutoInitial : true,
31547 initialColumnWidth : 0,
31548 currentSize : null,
31550 colYs : null, // array.
31557 bricks: null, //CompositeElement
31558 cols : 0, // array?
31559 // element : null, // wrapped now this.el
31560 _isLayoutInited : null,
31563 getAutoCreate : function(){
31567 cls: 'blog-masonary-wrapper ' + this.cls,
31569 cls : 'mas-boxes masonary'
31576 getChildContainer: function( )
31578 if (this.boxesEl) {
31579 return this.boxesEl;
31582 this.boxesEl = this.el.select('.mas-boxes').first();
31584 return this.boxesEl;
31588 initEvents : function()
31592 if(this.isAutoInitial){
31593 Roo.log('hook children rendered');
31594 this.on('childrenrendered', function() {
31595 Roo.log('children rendered');
31602 initial : function()
31604 this.reloadItems();
31606 this.currentSize = this.el.getBox(true);
31608 /// was window resize... - let's see if this works..
31609 Roo.EventManager.onWindowResize(this.resize, this);
31611 if(!this.isAutoInitial){
31616 this.layout.defer(500,this);
31619 reloadItems: function()
31621 this.bricks = this.el.select('.masonry-brick', true);
31623 this.bricks.each(function(b) {
31624 //Roo.log(b.getSize());
31625 if (!b.attr('originalwidth')) {
31626 b.attr('originalwidth', b.getSize().width);
31631 Roo.log(this.bricks.elements.length);
31634 resize : function()
31637 var cs = this.el.getBox(true);
31639 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31640 Roo.log("no change in with or X");
31643 this.currentSize = cs;
31647 layout : function()
31650 this._resetLayout();
31651 //this._manageStamps();
31653 // don't animate first layout
31654 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31655 this.layoutItems( isInstant );
31657 // flag for initalized
31658 this._isLayoutInited = true;
31661 layoutItems : function( isInstant )
31663 //var items = this._getItemsForLayout( this.items );
31664 // original code supports filtering layout items.. we just ignore it..
31666 this._layoutItems( this.bricks , isInstant );
31668 this._postLayout();
31670 _layoutItems : function ( items , isInstant)
31672 //this.fireEvent( 'layout', this, items );
31675 if ( !items || !items.elements.length ) {
31676 // no items, emit event with empty array
31681 items.each(function(item) {
31682 Roo.log("layout item");
31684 // get x/y object from method
31685 var position = this._getItemLayoutPosition( item );
31687 position.item = item;
31688 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31689 queue.push( position );
31692 this._processLayoutQueue( queue );
31694 /** Sets position of item in DOM
31695 * @param {Element} item
31696 * @param {Number} x - horizontal position
31697 * @param {Number} y - vertical position
31698 * @param {Boolean} isInstant - disables transitions
31700 _processLayoutQueue : function( queue )
31702 for ( var i=0, len = queue.length; i < len; i++ ) {
31703 var obj = queue[i];
31704 obj.item.position('absolute');
31705 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31711 * Any logic you want to do after each layout,
31712 * i.e. size the container
31714 _postLayout : function()
31716 this.resizeContainer();
31719 resizeContainer : function()
31721 if ( !this.isResizingContainer ) {
31724 var size = this._getContainerSize();
31726 this.el.setSize(size.width,size.height);
31727 this.boxesEl.setSize(size.width,size.height);
31733 _resetLayout : function()
31735 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31736 this.colWidth = this.el.getWidth();
31737 //this.gutter = this.el.getWidth();
31739 this.measureColumns();
31745 this.colYs.push( 0 );
31751 measureColumns : function()
31753 this.getContainerWidth();
31754 // if columnWidth is 0, default to outerWidth of first item
31755 if ( !this.columnWidth ) {
31756 var firstItem = this.bricks.first();
31757 Roo.log(firstItem);
31758 this.columnWidth = this.containerWidth;
31759 if (firstItem && firstItem.attr('originalwidth') ) {
31760 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31762 // columnWidth fall back to item of first element
31763 Roo.log("set column width?");
31764 this.initialColumnWidth = this.columnWidth ;
31766 // if first elem has no width, default to size of container
31771 if (this.initialColumnWidth) {
31772 this.columnWidth = this.initialColumnWidth;
31777 // column width is fixed at the top - however if container width get's smaller we should
31780 // this bit calcs how man columns..
31782 var columnWidth = this.columnWidth += this.gutter;
31784 // calculate columns
31785 var containerWidth = this.containerWidth + this.gutter;
31787 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31788 // fix rounding errors, typically with gutters
31789 var excess = columnWidth - containerWidth % columnWidth;
31792 // if overshoot is less than a pixel, round up, otherwise floor it
31793 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31794 cols = Math[ mathMethod ]( cols );
31795 this.cols = Math.max( cols, 1 );
31796 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31798 // padding positioning..
31799 var totalColWidth = this.cols * this.columnWidth;
31800 var padavail = this.containerWidth - totalColWidth;
31801 // so for 2 columns - we need 3 'pads'
31803 var padNeeded = (1+this.cols) * this.padWidth;
31805 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31807 this.columnWidth += padExtra
31808 //this.padWidth = Math.floor(padavail / ( this.cols));
31810 // adjust colum width so that padding is fixed??
31812 // we have 3 columns ... total = width * 3
31813 // we have X left over... that should be used by
31815 //if (this.expandC) {
31823 getContainerWidth : function()
31825 /* // container is parent if fit width
31826 var container = this.isFitWidth ? this.element.parentNode : this.element;
31827 // check that this.size and size are there
31828 // IE8 triggers resize on body size change, so they might not be
31830 var size = getSize( container ); //FIXME
31831 this.containerWidth = size && size.innerWidth; //FIXME
31834 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31838 _getItemLayoutPosition : function( item ) // what is item?
31840 // we resize the item to our columnWidth..
31842 item.setWidth(this.columnWidth);
31843 item.autoBoxAdjust = false;
31845 var sz = item.getSize();
31847 // how many columns does this brick span
31848 var remainder = this.containerWidth % this.columnWidth;
31850 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31851 // round if off by 1 pixel, otherwise use ceil
31852 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31853 colSpan = Math.min( colSpan, this.cols );
31855 // normally this should be '1' as we dont' currently allow multi width columns..
31857 var colGroup = this._getColGroup( colSpan );
31858 // get the minimum Y value from the columns
31859 var minimumY = Math.min.apply( Math, colGroup );
31860 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31862 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31864 // position the brick
31866 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31867 y: this.currentSize.y + minimumY + this.padHeight
31871 // apply setHeight to necessary columns
31872 var setHeight = minimumY + sz.height + this.padHeight;
31873 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31875 var setSpan = this.cols + 1 - colGroup.length;
31876 for ( var i = 0; i < setSpan; i++ ) {
31877 this.colYs[ shortColIndex + i ] = setHeight ;
31884 * @param {Number} colSpan - number of columns the element spans
31885 * @returns {Array} colGroup
31887 _getColGroup : function( colSpan )
31889 if ( colSpan < 2 ) {
31890 // if brick spans only one column, use all the column Ys
31895 // how many different places could this brick fit horizontally
31896 var groupCount = this.cols + 1 - colSpan;
31897 // for each group potential horizontal position
31898 for ( var i = 0; i < groupCount; i++ ) {
31899 // make an array of colY values for that one group
31900 var groupColYs = this.colYs.slice( i, i + colSpan );
31901 // and get the max value of the array
31902 colGroup[i] = Math.max.apply( Math, groupColYs );
31907 _manageStamp : function( stamp )
31909 var stampSize = stamp.getSize();
31910 var offset = stamp.getBox();
31911 // get the columns that this stamp affects
31912 var firstX = this.isOriginLeft ? offset.x : offset.right;
31913 var lastX = firstX + stampSize.width;
31914 var firstCol = Math.floor( firstX / this.columnWidth );
31915 firstCol = Math.max( 0, firstCol );
31917 var lastCol = Math.floor( lastX / this.columnWidth );
31918 // lastCol should not go over if multiple of columnWidth #425
31919 lastCol -= lastX % this.columnWidth ? 0 : 1;
31920 lastCol = Math.min( this.cols - 1, lastCol );
31922 // set colYs to bottom of the stamp
31923 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31926 for ( var i = firstCol; i <= lastCol; i++ ) {
31927 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31932 _getContainerSize : function()
31934 this.maxY = Math.max.apply( Math, this.colYs );
31939 if ( this.isFitWidth ) {
31940 size.width = this._getContainerFitWidth();
31946 _getContainerFitWidth : function()
31948 var unusedCols = 0;
31949 // count unused columns
31952 if ( this.colYs[i] !== 0 ) {
31957 // fit container to columns that have been used
31958 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31961 needsResizeLayout : function()
31963 var previousWidth = this.containerWidth;
31964 this.getContainerWidth();
31965 return previousWidth !== this.containerWidth;
31980 * @class Roo.bootstrap.MasonryBrick
31981 * @extends Roo.bootstrap.Component
31982 * Bootstrap MasonryBrick class
31985 * Create a new MasonryBrick
31986 * @param {Object} config The config object
31989 Roo.bootstrap.MasonryBrick = function(config){
31991 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31993 Roo.bootstrap.MasonryBrick.register(this);
31999 * When a MasonryBrick is clcik
32000 * @param {Roo.bootstrap.MasonryBrick} this
32001 * @param {Roo.EventObject} e
32007 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32010 * @cfg {String} title
32014 * @cfg {String} html
32018 * @cfg {String} bgimage
32022 * @cfg {String} videourl
32026 * @cfg {String} cls
32030 * @cfg {String} href
32034 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32039 * @cfg {String} placetitle (center|bottom)
32044 * @cfg {Boolean} isFitContainer defalut true
32046 isFitContainer : true,
32049 * @cfg {Boolean} preventDefault defalut false
32051 preventDefault : false,
32054 * @cfg {Boolean} inverse defalut false
32056 maskInverse : false,
32058 getAutoCreate : function()
32060 if(!this.isFitContainer){
32061 return this.getSplitAutoCreate();
32064 var cls = 'masonry-brick masonry-brick-full';
32066 if(this.href.length){
32067 cls += ' masonry-brick-link';
32070 if(this.bgimage.length){
32071 cls += ' masonry-brick-image';
32074 if(this.maskInverse){
32075 cls += ' mask-inverse';
32078 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32079 cls += ' enable-mask';
32083 cls += ' masonry-' + this.size + '-brick';
32086 if(this.placetitle.length){
32088 switch (this.placetitle) {
32090 cls += ' masonry-center-title';
32093 cls += ' masonry-bottom-title';
32100 if(!this.html.length && !this.bgimage.length){
32101 cls += ' masonry-center-title';
32104 if(!this.html.length && this.bgimage.length){
32105 cls += ' masonry-bottom-title';
32110 cls += ' ' + this.cls;
32114 tag: (this.href.length) ? 'a' : 'div',
32119 cls: 'masonry-brick-mask'
32123 cls: 'masonry-brick-paragraph',
32129 if(this.href.length){
32130 cfg.href = this.href;
32133 var cn = cfg.cn[1].cn;
32135 if(this.title.length){
32138 cls: 'masonry-brick-title',
32143 if(this.html.length){
32146 cls: 'masonry-brick-text',
32151 if (!this.title.length && !this.html.length) {
32152 cfg.cn[1].cls += ' hide';
32155 if(this.bgimage.length){
32158 cls: 'masonry-brick-image-view',
32163 if(this.videourl.length){
32164 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32165 // youtube support only?
32168 cls: 'masonry-brick-image-view',
32171 allowfullscreen : true
32179 getSplitAutoCreate : function()
32181 var cls = 'masonry-brick masonry-brick-split';
32183 if(this.href.length){
32184 cls += ' masonry-brick-link';
32187 if(this.bgimage.length){
32188 cls += ' masonry-brick-image';
32192 cls += ' masonry-' + this.size + '-brick';
32195 switch (this.placetitle) {
32197 cls += ' masonry-center-title';
32200 cls += ' masonry-bottom-title';
32203 if(!this.bgimage.length){
32204 cls += ' masonry-center-title';
32207 if(this.bgimage.length){
32208 cls += ' masonry-bottom-title';
32214 cls += ' ' + this.cls;
32218 tag: (this.href.length) ? 'a' : 'div',
32223 cls: 'masonry-brick-split-head',
32227 cls: 'masonry-brick-paragraph',
32234 cls: 'masonry-brick-split-body',
32240 if(this.href.length){
32241 cfg.href = this.href;
32244 if(this.title.length){
32245 cfg.cn[0].cn[0].cn.push({
32247 cls: 'masonry-brick-title',
32252 if(this.html.length){
32253 cfg.cn[1].cn.push({
32255 cls: 'masonry-brick-text',
32260 if(this.bgimage.length){
32261 cfg.cn[0].cn.push({
32263 cls: 'masonry-brick-image-view',
32268 if(this.videourl.length){
32269 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32270 // youtube support only?
32271 cfg.cn[0].cn.cn.push({
32273 cls: 'masonry-brick-image-view',
32276 allowfullscreen : true
32283 initEvents: function()
32285 switch (this.size) {
32318 this.el.on('touchstart', this.onTouchStart, this);
32319 this.el.on('touchmove', this.onTouchMove, this);
32320 this.el.on('touchend', this.onTouchEnd, this);
32321 this.el.on('contextmenu', this.onContextMenu, this);
32323 this.el.on('mouseenter' ,this.enter, this);
32324 this.el.on('mouseleave', this.leave, this);
32325 this.el.on('click', this.onClick, this);
32328 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32329 this.parent().bricks.push(this);
32334 onClick: function(e, el)
32336 var time = this.endTimer - this.startTimer;
32337 // Roo.log(e.preventDefault());
32340 e.preventDefault();
32345 if(!this.preventDefault){
32349 e.preventDefault();
32351 if (this.activcClass != '') {
32352 this.selectBrick();
32355 this.fireEvent('click', this);
32358 enter: function(e, el)
32360 e.preventDefault();
32362 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32366 if(this.bgimage.length && this.html.length){
32367 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32371 leave: function(e, el)
32373 e.preventDefault();
32375 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32379 if(this.bgimage.length && this.html.length){
32380 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32384 onTouchStart: function(e, el)
32386 // e.preventDefault();
32388 this.touchmoved = false;
32390 if(!this.isFitContainer){
32394 if(!this.bgimage.length || !this.html.length){
32398 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32400 this.timer = new Date().getTime();
32404 onTouchMove: function(e, el)
32406 this.touchmoved = true;
32409 onContextMenu : function(e,el)
32411 e.preventDefault();
32412 e.stopPropagation();
32416 onTouchEnd: function(e, el)
32418 // e.preventDefault();
32420 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32427 if(!this.bgimage.length || !this.html.length){
32429 if(this.href.length){
32430 window.location.href = this.href;
32436 if(!this.isFitContainer){
32440 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32442 window.location.href = this.href;
32445 //selection on single brick only
32446 selectBrick : function() {
32448 if (!this.parentId) {
32452 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32453 var index = m.selectedBrick.indexOf(this.id);
32456 m.selectedBrick.splice(index,1);
32457 this.el.removeClass(this.activeClass);
32461 for(var i = 0; i < m.selectedBrick.length; i++) {
32462 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32463 b.el.removeClass(b.activeClass);
32466 m.selectedBrick = [];
32468 m.selectedBrick.push(this.id);
32469 this.el.addClass(this.activeClass);
32475 Roo.apply(Roo.bootstrap.MasonryBrick, {
32478 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32480 * register a Masonry Brick
32481 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32484 register : function(brick)
32486 //this.groups[brick.id] = brick;
32487 this.groups.add(brick.id, brick);
32490 * fetch a masonry brick based on the masonry brick ID
32491 * @param {string} the masonry brick to add
32492 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32495 get: function(brick_id)
32497 // if (typeof(this.groups[brick_id]) == 'undefined') {
32500 // return this.groups[brick_id] ;
32502 if(this.groups.key(brick_id)) {
32503 return this.groups.key(brick_id);
32521 * @class Roo.bootstrap.Brick
32522 * @extends Roo.bootstrap.Component
32523 * Bootstrap Brick class
32526 * Create a new Brick
32527 * @param {Object} config The config object
32530 Roo.bootstrap.Brick = function(config){
32531 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32537 * When a Brick is click
32538 * @param {Roo.bootstrap.Brick} this
32539 * @param {Roo.EventObject} e
32545 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32548 * @cfg {String} title
32552 * @cfg {String} html
32556 * @cfg {String} bgimage
32560 * @cfg {String} cls
32564 * @cfg {String} href
32568 * @cfg {String} video
32572 * @cfg {Boolean} square
32576 getAutoCreate : function()
32578 var cls = 'roo-brick';
32580 if(this.href.length){
32581 cls += ' roo-brick-link';
32584 if(this.bgimage.length){
32585 cls += ' roo-brick-image';
32588 if(!this.html.length && !this.bgimage.length){
32589 cls += ' roo-brick-center-title';
32592 if(!this.html.length && this.bgimage.length){
32593 cls += ' roo-brick-bottom-title';
32597 cls += ' ' + this.cls;
32601 tag: (this.href.length) ? 'a' : 'div',
32606 cls: 'roo-brick-paragraph',
32612 if(this.href.length){
32613 cfg.href = this.href;
32616 var cn = cfg.cn[0].cn;
32618 if(this.title.length){
32621 cls: 'roo-brick-title',
32626 if(this.html.length){
32629 cls: 'roo-brick-text',
32636 if(this.bgimage.length){
32639 cls: 'roo-brick-image-view',
32647 initEvents: function()
32649 if(this.title.length || this.html.length){
32650 this.el.on('mouseenter' ,this.enter, this);
32651 this.el.on('mouseleave', this.leave, this);
32654 Roo.EventManager.onWindowResize(this.resize, this);
32656 if(this.bgimage.length){
32657 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32658 this.imageEl.on('load', this.onImageLoad, this);
32665 onImageLoad : function()
32670 resize : function()
32672 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32674 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32676 if(this.bgimage.length){
32677 var image = this.el.select('.roo-brick-image-view', true).first();
32679 image.setWidth(paragraph.getWidth());
32682 image.setHeight(paragraph.getWidth());
32685 this.el.setHeight(image.getHeight());
32686 paragraph.setHeight(image.getHeight());
32692 enter: function(e, el)
32694 e.preventDefault();
32696 if(this.bgimage.length){
32697 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32698 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32702 leave: function(e, el)
32704 e.preventDefault();
32706 if(this.bgimage.length){
32707 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32708 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32724 * @class Roo.bootstrap.NumberField
32725 * @extends Roo.bootstrap.Input
32726 * Bootstrap NumberField class
32732 * Create a new NumberField
32733 * @param {Object} config The config object
32736 Roo.bootstrap.NumberField = function(config){
32737 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32740 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32743 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32745 allowDecimals : true,
32747 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32749 decimalSeparator : ".",
32751 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32753 decimalPrecision : 2,
32755 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32757 allowNegative : true,
32759 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32761 minValue : Number.NEGATIVE_INFINITY,
32763 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32765 maxValue : Number.MAX_VALUE,
32767 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32769 minText : "The minimum value for this field is {0}",
32771 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32773 maxText : "The maximum value for this field is {0}",
32775 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32776 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32778 nanText : "{0} is not a valid number",
32780 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32785 initEvents : function()
32787 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32789 var allowed = "0123456789";
32791 if(this.allowDecimals){
32792 allowed += this.decimalSeparator;
32795 if(this.allowNegative){
32799 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32801 var keyPress = function(e){
32803 var k = e.getKey();
32805 var c = e.getCharCode();
32808 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32809 allowed.indexOf(String.fromCharCode(c)) === -1
32815 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32819 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32824 this.el.on("keypress", keyPress, this);
32827 validateValue : function(value)
32830 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32834 var num = this.parseValue(value);
32837 this.markInvalid(String.format(this.nanText, value));
32841 if(num < this.minValue){
32842 this.markInvalid(String.format(this.minText, this.minValue));
32846 if(num > this.maxValue){
32847 this.markInvalid(String.format(this.maxText, this.maxValue));
32854 getValue : function()
32856 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32859 parseValue : function(value)
32861 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32862 return isNaN(value) ? '' : value;
32865 fixPrecision : function(value)
32867 var nan = isNaN(value);
32869 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32870 return nan ? '' : value;
32872 return parseFloat(value).toFixed(this.decimalPrecision);
32875 setValue : function(v)
32877 v = this.fixPrecision(v);
32878 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32881 decimalPrecisionFcn : function(v)
32883 return Math.floor(v);
32886 beforeBlur : function()
32892 var v = this.parseValue(this.getRawValue());
32907 * @class Roo.bootstrap.DocumentSlider
32908 * @extends Roo.bootstrap.Component
32909 * Bootstrap DocumentSlider class
32912 * Create a new DocumentViewer
32913 * @param {Object} config The config object
32916 Roo.bootstrap.DocumentSlider = function(config){
32917 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32924 * Fire after initEvent
32925 * @param {Roo.bootstrap.DocumentSlider} this
32930 * Fire after update
32931 * @param {Roo.bootstrap.DocumentSlider} this
32937 * @param {Roo.bootstrap.DocumentSlider} this
32943 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32949 getAutoCreate : function()
32953 cls : 'roo-document-slider',
32957 cls : 'roo-document-slider-header',
32961 cls : 'roo-document-slider-header-title'
32967 cls : 'roo-document-slider-body',
32971 cls : 'roo-document-slider-prev',
32975 cls : 'fa fa-chevron-left'
32981 cls : 'roo-document-slider-thumb',
32985 cls : 'roo-document-slider-image'
32991 cls : 'roo-document-slider-next',
32995 cls : 'fa fa-chevron-right'
33007 initEvents : function()
33009 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33010 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33012 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33013 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33015 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33016 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33018 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33019 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33021 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33022 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33024 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33025 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33027 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33028 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33030 this.thumbEl.on('click', this.onClick, this);
33032 this.prevIndicator.on('click', this.prev, this);
33034 this.nextIndicator.on('click', this.next, this);
33038 initial : function()
33040 if(this.files.length){
33041 this.indicator = 1;
33045 this.fireEvent('initial', this);
33048 update : function()
33050 this.imageEl.attr('src', this.files[this.indicator - 1]);
33052 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33054 this.prevIndicator.show();
33056 if(this.indicator == 1){
33057 this.prevIndicator.hide();
33060 this.nextIndicator.show();
33062 if(this.indicator == this.files.length){
33063 this.nextIndicator.hide();
33066 this.thumbEl.scrollTo('top');
33068 this.fireEvent('update', this);
33071 onClick : function(e)
33073 e.preventDefault();
33075 this.fireEvent('click', this);
33080 e.preventDefault();
33082 this.indicator = Math.max(1, this.indicator - 1);
33089 e.preventDefault();
33091 this.indicator = Math.min(this.files.length, this.indicator + 1);
33105 * @class Roo.bootstrap.RadioSet
33106 * @extends Roo.bootstrap.Input
33107 * Bootstrap RadioSet class
33108 * @cfg {String} indicatorpos (left|right) default left
33109 * @cfg {Boolean} inline (true|false) inline the element (default true)
33110 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33112 * Create a new RadioSet
33113 * @param {Object} config The config object
33116 Roo.bootstrap.RadioSet = function(config){
33118 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33122 Roo.bootstrap.RadioSet.register(this);
33127 * Fires when the element is checked or unchecked.
33128 * @param {Roo.bootstrap.RadioSet} this This radio
33129 * @param {Roo.bootstrap.Radio} item The checked item
33136 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33144 indicatorpos : 'left',
33146 getAutoCreate : function()
33150 cls : 'roo-radio-set-label',
33154 html : this.fieldLabel
33159 if(this.indicatorpos == 'left'){
33162 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33163 tooltip : 'This field is required'
33168 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33169 tooltip : 'This field is required'
33175 cls : 'roo-radio-set-items'
33178 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33180 if (align === 'left' && this.fieldLabel.length) {
33183 cls : "roo-radio-set-right",
33189 if(this.labelWidth > 12){
33190 label.style = "width: " + this.labelWidth + 'px';
33193 if(this.labelWidth < 13 && this.labelmd == 0){
33194 this.labelmd = this.labelWidth;
33197 if(this.labellg > 0){
33198 label.cls += ' col-lg-' + this.labellg;
33199 items.cls += ' col-lg-' + (12 - this.labellg);
33202 if(this.labelmd > 0){
33203 label.cls += ' col-md-' + this.labelmd;
33204 items.cls += ' col-md-' + (12 - this.labelmd);
33207 if(this.labelsm > 0){
33208 label.cls += ' col-sm-' + this.labelsm;
33209 items.cls += ' col-sm-' + (12 - this.labelsm);
33212 if(this.labelxs > 0){
33213 label.cls += ' col-xs-' + this.labelxs;
33214 items.cls += ' col-xs-' + (12 - this.labelxs);
33220 cls : 'roo-radio-set',
33224 cls : 'roo-radio-set-input',
33227 value : this.value ? this.value : ''
33234 if(this.weight.length){
33235 cfg.cls += ' roo-radio-' + this.weight;
33239 cfg.cls += ' roo-radio-set-inline';
33246 initEvents : function()
33248 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33249 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33251 if(!this.fieldLabel.length){
33252 this.labelEl.hide();
33255 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33256 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33258 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
33259 this.indicatorEl().hide();
33261 this.originalValue = this.getValue();
33265 inputEl: function ()
33267 return this.el.select('.roo-radio-set-input', true).first();
33270 getChildContainer : function()
33272 return this.itemsEl;
33275 register : function(item)
33277 this.radioes.push(item);
33281 validate : function()
33285 Roo.each(this.radioes, function(i){
33294 if(this.allowBlank) {
33298 if(this.disabled || valid){
33303 this.markInvalid();
33308 markValid : function()
33310 if(this.labelEl.isVisible(true)){
33311 this.indicatorEl().hide();
33314 this.el.removeClass([this.invalidClass, this.validClass]);
33315 this.el.addClass(this.validClass);
33317 this.fireEvent('valid', this);
33320 markInvalid : function(msg)
33322 if(this.allowBlank || this.disabled){
33326 if(this.labelEl.isVisible(true)){
33327 this.indicatorEl().show();
33330 this.el.removeClass([this.invalidClass, this.validClass]);
33331 this.el.addClass(this.invalidClass);
33333 this.fireEvent('invalid', this, msg);
33337 setValue : function(v, suppressEvent)
33341 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33344 Roo.each(this.radioes, function(i){
33347 i.el.removeClass('checked');
33349 if(i.value === v || i.value.toString() === v.toString()){
33351 i.el.addClass('checked');
33353 if(suppressEvent !== true){
33354 this.fireEvent('check', this, i);
33363 clearInvalid : function(){
33365 if(!this.el || this.preventMark){
33369 this.el.removeClass([this.invalidClass]);
33371 this.fireEvent('valid', this);
33376 Roo.apply(Roo.bootstrap.RadioSet, {
33380 register : function(set)
33382 this.groups[set.name] = set;
33385 get: function(name)
33387 if (typeof(this.groups[name]) == 'undefined') {
33391 return this.groups[name] ;
33397 * Ext JS Library 1.1.1
33398 * Copyright(c) 2006-2007, Ext JS, LLC.
33400 * Originally Released Under LGPL - original licence link has changed is not relivant.
33403 * <script type="text/javascript">
33408 * @class Roo.bootstrap.SplitBar
33409 * @extends Roo.util.Observable
33410 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33414 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33415 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33416 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33417 split.minSize = 100;
33418 split.maxSize = 600;
33419 split.animate = true;
33420 split.on('moved', splitterMoved);
33423 * Create a new SplitBar
33424 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33425 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33426 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33427 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33428 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33429 position of the SplitBar).
33431 Roo.bootstrap.SplitBar = function(cfg){
33436 // dragElement : elm
33437 // resizingElement: el,
33439 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33440 // placement : Roo.bootstrap.SplitBar.LEFT ,
33441 // existingProxy ???
33444 this.el = Roo.get(cfg.dragElement, true);
33445 this.el.dom.unselectable = "on";
33447 this.resizingEl = Roo.get(cfg.resizingElement, true);
33451 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33452 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33455 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33458 * The minimum size of the resizing element. (Defaults to 0)
33464 * The maximum size of the resizing element. (Defaults to 2000)
33467 this.maxSize = 2000;
33470 * Whether to animate the transition to the new size
33473 this.animate = false;
33476 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33479 this.useShim = false;
33484 if(!cfg.existingProxy){
33486 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33488 this.proxy = Roo.get(cfg.existingProxy).dom;
33491 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33494 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33497 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33500 this.dragSpecs = {};
33503 * @private The adapter to use to positon and resize elements
33505 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33506 this.adapter.init(this);
33508 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33510 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33511 this.el.addClass("roo-splitbar-h");
33514 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33515 this.el.addClass("roo-splitbar-v");
33521 * Fires when the splitter is moved (alias for {@link #event-moved})
33522 * @param {Roo.bootstrap.SplitBar} this
33523 * @param {Number} newSize the new width or height
33528 * Fires when the splitter is moved
33529 * @param {Roo.bootstrap.SplitBar} this
33530 * @param {Number} newSize the new width or height
33534 * @event beforeresize
33535 * Fires before the splitter is dragged
33536 * @param {Roo.bootstrap.SplitBar} this
33538 "beforeresize" : true,
33540 "beforeapply" : true
33543 Roo.util.Observable.call(this);
33546 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33547 onStartProxyDrag : function(x, y){
33548 this.fireEvent("beforeresize", this);
33550 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33552 o.enableDisplayMode("block");
33553 // all splitbars share the same overlay
33554 Roo.bootstrap.SplitBar.prototype.overlay = o;
33556 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33557 this.overlay.show();
33558 Roo.get(this.proxy).setDisplayed("block");
33559 var size = this.adapter.getElementSize(this);
33560 this.activeMinSize = this.getMinimumSize();;
33561 this.activeMaxSize = this.getMaximumSize();;
33562 var c1 = size - this.activeMinSize;
33563 var c2 = Math.max(this.activeMaxSize - size, 0);
33564 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33565 this.dd.resetConstraints();
33566 this.dd.setXConstraint(
33567 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33568 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33570 this.dd.setYConstraint(0, 0);
33572 this.dd.resetConstraints();
33573 this.dd.setXConstraint(0, 0);
33574 this.dd.setYConstraint(
33575 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33576 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33579 this.dragSpecs.startSize = size;
33580 this.dragSpecs.startPoint = [x, y];
33581 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33585 * @private Called after the drag operation by the DDProxy
33587 onEndProxyDrag : function(e){
33588 Roo.get(this.proxy).setDisplayed(false);
33589 var endPoint = Roo.lib.Event.getXY(e);
33591 this.overlay.hide();
33594 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33595 newSize = this.dragSpecs.startSize +
33596 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33597 endPoint[0] - this.dragSpecs.startPoint[0] :
33598 this.dragSpecs.startPoint[0] - endPoint[0]
33601 newSize = this.dragSpecs.startSize +
33602 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33603 endPoint[1] - this.dragSpecs.startPoint[1] :
33604 this.dragSpecs.startPoint[1] - endPoint[1]
33607 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33608 if(newSize != this.dragSpecs.startSize){
33609 if(this.fireEvent('beforeapply', this, newSize) !== false){
33610 this.adapter.setElementSize(this, newSize);
33611 this.fireEvent("moved", this, newSize);
33612 this.fireEvent("resize", this, newSize);
33618 * Get the adapter this SplitBar uses
33619 * @return The adapter object
33621 getAdapter : function(){
33622 return this.adapter;
33626 * Set the adapter this SplitBar uses
33627 * @param {Object} adapter A SplitBar adapter object
33629 setAdapter : function(adapter){
33630 this.adapter = adapter;
33631 this.adapter.init(this);
33635 * Gets the minimum size for the resizing element
33636 * @return {Number} The minimum size
33638 getMinimumSize : function(){
33639 return this.minSize;
33643 * Sets the minimum size for the resizing element
33644 * @param {Number} minSize The minimum size
33646 setMinimumSize : function(minSize){
33647 this.minSize = minSize;
33651 * Gets the maximum size for the resizing element
33652 * @return {Number} The maximum size
33654 getMaximumSize : function(){
33655 return this.maxSize;
33659 * Sets the maximum size for the resizing element
33660 * @param {Number} maxSize The maximum size
33662 setMaximumSize : function(maxSize){
33663 this.maxSize = maxSize;
33667 * Sets the initialize size for the resizing element
33668 * @param {Number} size The initial size
33670 setCurrentSize : function(size){
33671 var oldAnimate = this.animate;
33672 this.animate = false;
33673 this.adapter.setElementSize(this, size);
33674 this.animate = oldAnimate;
33678 * Destroy this splitbar.
33679 * @param {Boolean} removeEl True to remove the element
33681 destroy : function(removeEl){
33683 this.shim.remove();
33686 this.proxy.parentNode.removeChild(this.proxy);
33694 * @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.
33696 Roo.bootstrap.SplitBar.createProxy = function(dir){
33697 var proxy = new Roo.Element(document.createElement("div"));
33698 proxy.unselectable();
33699 var cls = 'roo-splitbar-proxy';
33700 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33701 document.body.appendChild(proxy.dom);
33706 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33707 * Default Adapter. It assumes the splitter and resizing element are not positioned
33708 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33710 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33713 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33714 // do nothing for now
33715 init : function(s){
33719 * Called before drag operations to get the current size of the resizing element.
33720 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33722 getElementSize : function(s){
33723 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33724 return s.resizingEl.getWidth();
33726 return s.resizingEl.getHeight();
33731 * Called after drag operations to set the size of the resizing element.
33732 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33733 * @param {Number} newSize The new size to set
33734 * @param {Function} onComplete A function to be invoked when resizing is complete
33736 setElementSize : function(s, newSize, onComplete){
33737 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33739 s.resizingEl.setWidth(newSize);
33741 onComplete(s, newSize);
33744 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33749 s.resizingEl.setHeight(newSize);
33751 onComplete(s, newSize);
33754 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33761 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33762 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33763 * Adapter that moves the splitter element to align with the resized sizing element.
33764 * Used with an absolute positioned SplitBar.
33765 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33766 * document.body, make sure you assign an id to the body element.
33768 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33769 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33770 this.container = Roo.get(container);
33773 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33774 init : function(s){
33775 this.basic.init(s);
33778 getElementSize : function(s){
33779 return this.basic.getElementSize(s);
33782 setElementSize : function(s, newSize, onComplete){
33783 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33786 moveSplitter : function(s){
33787 var yes = Roo.bootstrap.SplitBar;
33788 switch(s.placement){
33790 s.el.setX(s.resizingEl.getRight());
33793 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33796 s.el.setY(s.resizingEl.getBottom());
33799 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33806 * Orientation constant - Create a vertical SplitBar
33810 Roo.bootstrap.SplitBar.VERTICAL = 1;
33813 * Orientation constant - Create a horizontal SplitBar
33817 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33820 * Placement constant - The resizing element is to the left of the splitter element
33824 Roo.bootstrap.SplitBar.LEFT = 1;
33827 * Placement constant - The resizing element is to the right of the splitter element
33831 Roo.bootstrap.SplitBar.RIGHT = 2;
33834 * Placement constant - The resizing element is positioned above the splitter element
33838 Roo.bootstrap.SplitBar.TOP = 3;
33841 * Placement constant - The resizing element is positioned under splitter element
33845 Roo.bootstrap.SplitBar.BOTTOM = 4;
33846 Roo.namespace("Roo.bootstrap.layout");/*
33848 * Ext JS Library 1.1.1
33849 * Copyright(c) 2006-2007, Ext JS, LLC.
33851 * Originally Released Under LGPL - original licence link has changed is not relivant.
33854 * <script type="text/javascript">
33858 * @class Roo.bootstrap.layout.Manager
33859 * @extends Roo.bootstrap.Component
33860 * Base class for layout managers.
33862 Roo.bootstrap.layout.Manager = function(config)
33864 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33870 /** false to disable window resize monitoring @type Boolean */
33871 this.monitorWindowResize = true;
33876 * Fires when a layout is performed.
33877 * @param {Roo.LayoutManager} this
33881 * @event regionresized
33882 * Fires when the user resizes a region.
33883 * @param {Roo.LayoutRegion} region The resized region
33884 * @param {Number} newSize The new size (width for east/west, height for north/south)
33886 "regionresized" : true,
33888 * @event regioncollapsed
33889 * Fires when a region is collapsed.
33890 * @param {Roo.LayoutRegion} region The collapsed region
33892 "regioncollapsed" : true,
33894 * @event regionexpanded
33895 * Fires when a region is expanded.
33896 * @param {Roo.LayoutRegion} region The expanded region
33898 "regionexpanded" : true
33900 this.updating = false;
33903 this.el = Roo.get(config.el);
33909 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33914 monitorWindowResize : true,
33920 onRender : function(ct, position)
33923 this.el = Roo.get(ct);
33926 //this.fireEvent('render',this);
33930 initEvents: function()
33934 // ie scrollbar fix
33935 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33936 document.body.scroll = "no";
33937 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33938 this.el.position('relative');
33940 this.id = this.el.id;
33941 this.el.addClass("roo-layout-container");
33942 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33943 if(this.el.dom != document.body ) {
33944 this.el.on('resize', this.layout,this);
33945 this.el.on('show', this.layout,this);
33951 * Returns true if this layout is currently being updated
33952 * @return {Boolean}
33954 isUpdating : function(){
33955 return this.updating;
33959 * Suspend the LayoutManager from doing auto-layouts while
33960 * making multiple add or remove calls
33962 beginUpdate : function(){
33963 this.updating = true;
33967 * Restore auto-layouts and optionally disable the manager from performing a layout
33968 * @param {Boolean} noLayout true to disable a layout update
33970 endUpdate : function(noLayout){
33971 this.updating = false;
33977 layout: function(){
33981 onRegionResized : function(region, newSize){
33982 this.fireEvent("regionresized", region, newSize);
33986 onRegionCollapsed : function(region){
33987 this.fireEvent("regioncollapsed", region);
33990 onRegionExpanded : function(region){
33991 this.fireEvent("regionexpanded", region);
33995 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33996 * performs box-model adjustments.
33997 * @return {Object} The size as an object {width: (the width), height: (the height)}
33999 getViewSize : function()
34002 if(this.el.dom != document.body){
34003 size = this.el.getSize();
34005 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34007 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34008 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34013 * Returns the Element this layout is bound to.
34014 * @return {Roo.Element}
34016 getEl : function(){
34021 * Returns the specified region.
34022 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34023 * @return {Roo.LayoutRegion}
34025 getRegion : function(target){
34026 return this.regions[target.toLowerCase()];
34029 onWindowResize : function(){
34030 if(this.monitorWindowResize){
34037 * Ext JS Library 1.1.1
34038 * Copyright(c) 2006-2007, Ext JS, LLC.
34040 * Originally Released Under LGPL - original licence link has changed is not relivant.
34043 * <script type="text/javascript">
34046 * @class Roo.bootstrap.layout.Border
34047 * @extends Roo.bootstrap.layout.Manager
34048 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34049 * please see: examples/bootstrap/nested.html<br><br>
34051 <b>The container the layout is rendered into can be either the body element or any other element.
34052 If it is not the body element, the container needs to either be an absolute positioned element,
34053 or you will need to add "position:relative" to the css of the container. You will also need to specify
34054 the container size if it is not the body element.</b>
34057 * Create a new Border
34058 * @param {Object} config Configuration options
34060 Roo.bootstrap.layout.Border = function(config){
34061 config = config || {};
34062 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34066 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34067 if(config[region]){
34068 config[region].region = region;
34069 this.addRegion(config[region]);
34075 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34077 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34079 * Creates and adds a new region if it doesn't already exist.
34080 * @param {String} target The target region key (north, south, east, west or center).
34081 * @param {Object} config The regions config object
34082 * @return {BorderLayoutRegion} The new region
34084 addRegion : function(config)
34086 if(!this.regions[config.region]){
34087 var r = this.factory(config);
34088 this.bindRegion(r);
34090 return this.regions[config.region];
34094 bindRegion : function(r){
34095 this.regions[r.config.region] = r;
34097 r.on("visibilitychange", this.layout, this);
34098 r.on("paneladded", this.layout, this);
34099 r.on("panelremoved", this.layout, this);
34100 r.on("invalidated", this.layout, this);
34101 r.on("resized", this.onRegionResized, this);
34102 r.on("collapsed", this.onRegionCollapsed, this);
34103 r.on("expanded", this.onRegionExpanded, this);
34107 * Performs a layout update.
34109 layout : function()
34111 if(this.updating) {
34115 // render all the rebions if they have not been done alreayd?
34116 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34117 if(this.regions[region] && !this.regions[region].bodyEl){
34118 this.regions[region].onRender(this.el)
34122 var size = this.getViewSize();
34123 var w = size.width;
34124 var h = size.height;
34129 //var x = 0, y = 0;
34131 var rs = this.regions;
34132 var north = rs["north"];
34133 var south = rs["south"];
34134 var west = rs["west"];
34135 var east = rs["east"];
34136 var center = rs["center"];
34137 //if(this.hideOnLayout){ // not supported anymore
34138 //c.el.setStyle("display", "none");
34140 if(north && north.isVisible()){
34141 var b = north.getBox();
34142 var m = north.getMargins();
34143 b.width = w - (m.left+m.right);
34146 centerY = b.height + b.y + m.bottom;
34147 centerH -= centerY;
34148 north.updateBox(this.safeBox(b));
34150 if(south && south.isVisible()){
34151 var b = south.getBox();
34152 var m = south.getMargins();
34153 b.width = w - (m.left+m.right);
34155 var totalHeight = (b.height + m.top + m.bottom);
34156 b.y = h - totalHeight + m.top;
34157 centerH -= totalHeight;
34158 south.updateBox(this.safeBox(b));
34160 if(west && west.isVisible()){
34161 var b = west.getBox();
34162 var m = west.getMargins();
34163 b.height = centerH - (m.top+m.bottom);
34165 b.y = centerY + m.top;
34166 var totalWidth = (b.width + m.left + m.right);
34167 centerX += totalWidth;
34168 centerW -= totalWidth;
34169 west.updateBox(this.safeBox(b));
34171 if(east && east.isVisible()){
34172 var b = east.getBox();
34173 var m = east.getMargins();
34174 b.height = centerH - (m.top+m.bottom);
34175 var totalWidth = (b.width + m.left + m.right);
34176 b.x = w - totalWidth + m.left;
34177 b.y = centerY + m.top;
34178 centerW -= totalWidth;
34179 east.updateBox(this.safeBox(b));
34182 var m = center.getMargins();
34184 x: centerX + m.left,
34185 y: centerY + m.top,
34186 width: centerW - (m.left+m.right),
34187 height: centerH - (m.top+m.bottom)
34189 //if(this.hideOnLayout){
34190 //center.el.setStyle("display", "block");
34192 center.updateBox(this.safeBox(centerBox));
34195 this.fireEvent("layout", this);
34199 safeBox : function(box){
34200 box.width = Math.max(0, box.width);
34201 box.height = Math.max(0, box.height);
34206 * Adds a ContentPanel (or subclass) to this layout.
34207 * @param {String} target The target region key (north, south, east, west or center).
34208 * @param {Roo.ContentPanel} panel The panel to add
34209 * @return {Roo.ContentPanel} The added panel
34211 add : function(target, panel){
34213 target = target.toLowerCase();
34214 return this.regions[target].add(panel);
34218 * Remove a ContentPanel (or subclass) to this layout.
34219 * @param {String} target The target region key (north, south, east, west or center).
34220 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34221 * @return {Roo.ContentPanel} The removed panel
34223 remove : function(target, panel){
34224 target = target.toLowerCase();
34225 return this.regions[target].remove(panel);
34229 * Searches all regions for a panel with the specified id
34230 * @param {String} panelId
34231 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34233 findPanel : function(panelId){
34234 var rs = this.regions;
34235 for(var target in rs){
34236 if(typeof rs[target] != "function"){
34237 var p = rs[target].getPanel(panelId);
34247 * Searches all regions for a panel with the specified id and activates (shows) it.
34248 * @param {String/ContentPanel} panelId The panels id or the panel itself
34249 * @return {Roo.ContentPanel} The shown panel or null
34251 showPanel : function(panelId) {
34252 var rs = this.regions;
34253 for(var target in rs){
34254 var r = rs[target];
34255 if(typeof r != "function"){
34256 if(r.hasPanel(panelId)){
34257 return r.showPanel(panelId);
34265 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34266 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34269 restoreState : function(provider){
34271 provider = Roo.state.Manager;
34273 var sm = new Roo.LayoutStateManager();
34274 sm.init(this, provider);
34280 * Adds a xtype elements to the layout.
34284 xtype : 'ContentPanel',
34291 xtype : 'NestedLayoutPanel',
34297 items : [ ... list of content panels or nested layout panels.. ]
34301 * @param {Object} cfg Xtype definition of item to add.
34303 addxtype : function(cfg)
34305 // basically accepts a pannel...
34306 // can accept a layout region..!?!?
34307 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34310 // theory? children can only be panels??
34312 //if (!cfg.xtype.match(/Panel$/)) {
34317 if (typeof(cfg.region) == 'undefined') {
34318 Roo.log("Failed to add Panel, region was not set");
34322 var region = cfg.region;
34328 xitems = cfg.items;
34335 case 'Content': // ContentPanel (el, cfg)
34336 case 'Scroll': // ContentPanel (el, cfg)
34338 cfg.autoCreate = true;
34339 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34341 // var el = this.el.createChild();
34342 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34345 this.add(region, ret);
34349 case 'TreePanel': // our new panel!
34350 cfg.el = this.el.createChild();
34351 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34352 this.add(region, ret);
34357 // create a new Layout (which is a Border Layout...
34359 var clayout = cfg.layout;
34360 clayout.el = this.el.createChild();
34361 clayout.items = clayout.items || [];
34365 // replace this exitems with the clayout ones..
34366 xitems = clayout.items;
34368 // force background off if it's in center...
34369 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34370 cfg.background = false;
34372 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34375 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34376 //console.log('adding nested layout panel ' + cfg.toSource());
34377 this.add(region, ret);
34378 nb = {}; /// find first...
34383 // needs grid and region
34385 //var el = this.getRegion(region).el.createChild();
34387 *var el = this.el.createChild();
34388 // create the grid first...
34389 cfg.grid.container = el;
34390 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34393 if (region == 'center' && this.active ) {
34394 cfg.background = false;
34397 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34399 this.add(region, ret);
34401 if (cfg.background) {
34402 // render grid on panel activation (if panel background)
34403 ret.on('activate', function(gp) {
34404 if (!gp.grid.rendered) {
34405 // gp.grid.render(el);
34409 // cfg.grid.render(el);
34415 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34416 // it was the old xcomponent building that caused this before.
34417 // espeically if border is the top element in the tree.
34427 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34429 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34430 this.add(region, ret);
34434 throw "Can not add '" + cfg.xtype + "' to Border";
34440 this.beginUpdate();
34444 Roo.each(xitems, function(i) {
34445 region = nb && i.region ? i.region : false;
34447 var add = ret.addxtype(i);
34450 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34451 if (!i.background) {
34452 abn[region] = nb[region] ;
34459 // make the last non-background panel active..
34460 //if (nb) { Roo.log(abn); }
34463 for(var r in abn) {
34464 region = this.getRegion(r);
34466 // tried using nb[r], but it does not work..
34468 region.showPanel(abn[r]);
34479 factory : function(cfg)
34482 var validRegions = Roo.bootstrap.layout.Border.regions;
34484 var target = cfg.region;
34487 var r = Roo.bootstrap.layout;
34491 return new r.North(cfg);
34493 return new r.South(cfg);
34495 return new r.East(cfg);
34497 return new r.West(cfg);
34499 return new r.Center(cfg);
34501 throw 'Layout region "'+target+'" not supported.';
34508 * Ext JS Library 1.1.1
34509 * Copyright(c) 2006-2007, Ext JS, LLC.
34511 * Originally Released Under LGPL - original licence link has changed is not relivant.
34514 * <script type="text/javascript">
34518 * @class Roo.bootstrap.layout.Basic
34519 * @extends Roo.util.Observable
34520 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34521 * and does not have a titlebar, tabs or any other features. All it does is size and position
34522 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34523 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34524 * @cfg {string} region the region that it inhabits..
34525 * @cfg {bool} skipConfig skip config?
34529 Roo.bootstrap.layout.Basic = function(config){
34531 this.mgr = config.mgr;
34533 this.position = config.region;
34535 var skipConfig = config.skipConfig;
34539 * @scope Roo.BasicLayoutRegion
34543 * @event beforeremove
34544 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34545 * @param {Roo.LayoutRegion} this
34546 * @param {Roo.ContentPanel} panel The panel
34547 * @param {Object} e The cancel event object
34549 "beforeremove" : true,
34551 * @event invalidated
34552 * Fires when the layout for this region is changed.
34553 * @param {Roo.LayoutRegion} this
34555 "invalidated" : true,
34557 * @event visibilitychange
34558 * Fires when this region is shown or hidden
34559 * @param {Roo.LayoutRegion} this
34560 * @param {Boolean} visibility true or false
34562 "visibilitychange" : true,
34564 * @event paneladded
34565 * Fires when a panel is added.
34566 * @param {Roo.LayoutRegion} this
34567 * @param {Roo.ContentPanel} panel The panel
34569 "paneladded" : true,
34571 * @event panelremoved
34572 * Fires when a panel is removed.
34573 * @param {Roo.LayoutRegion} this
34574 * @param {Roo.ContentPanel} panel The panel
34576 "panelremoved" : true,
34578 * @event beforecollapse
34579 * Fires when this region before collapse.
34580 * @param {Roo.LayoutRegion} this
34582 "beforecollapse" : true,
34585 * Fires when this region is collapsed.
34586 * @param {Roo.LayoutRegion} this
34588 "collapsed" : true,
34591 * Fires when this region is expanded.
34592 * @param {Roo.LayoutRegion} this
34597 * Fires when this region is slid into view.
34598 * @param {Roo.LayoutRegion} this
34600 "slideshow" : true,
34603 * Fires when this region slides out of view.
34604 * @param {Roo.LayoutRegion} this
34606 "slidehide" : true,
34608 * @event panelactivated
34609 * Fires when a panel is activated.
34610 * @param {Roo.LayoutRegion} this
34611 * @param {Roo.ContentPanel} panel The activated panel
34613 "panelactivated" : true,
34616 * Fires when the user resizes this region.
34617 * @param {Roo.LayoutRegion} this
34618 * @param {Number} newSize The new size (width for east/west, height for north/south)
34622 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34623 this.panels = new Roo.util.MixedCollection();
34624 this.panels.getKey = this.getPanelId.createDelegate(this);
34626 this.activePanel = null;
34627 // ensure listeners are added...
34629 if (config.listeners || config.events) {
34630 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34631 listeners : config.listeners || {},
34632 events : config.events || {}
34636 if(skipConfig !== true){
34637 this.applyConfig(config);
34641 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34643 getPanelId : function(p){
34647 applyConfig : function(config){
34648 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34649 this.config = config;
34654 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34655 * the width, for horizontal (north, south) the height.
34656 * @param {Number} newSize The new width or height
34658 resizeTo : function(newSize){
34659 var el = this.el ? this.el :
34660 (this.activePanel ? this.activePanel.getEl() : null);
34662 switch(this.position){
34665 el.setWidth(newSize);
34666 this.fireEvent("resized", this, newSize);
34670 el.setHeight(newSize);
34671 this.fireEvent("resized", this, newSize);
34677 getBox : function(){
34678 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34681 getMargins : function(){
34682 return this.margins;
34685 updateBox : function(box){
34687 var el = this.activePanel.getEl();
34688 el.dom.style.left = box.x + "px";
34689 el.dom.style.top = box.y + "px";
34690 this.activePanel.setSize(box.width, box.height);
34694 * Returns the container element for this region.
34695 * @return {Roo.Element}
34697 getEl : function(){
34698 return this.activePanel;
34702 * Returns true if this region is currently visible.
34703 * @return {Boolean}
34705 isVisible : function(){
34706 return this.activePanel ? true : false;
34709 setActivePanel : function(panel){
34710 panel = this.getPanel(panel);
34711 if(this.activePanel && this.activePanel != panel){
34712 this.activePanel.setActiveState(false);
34713 this.activePanel.getEl().setLeftTop(-10000,-10000);
34715 this.activePanel = panel;
34716 panel.setActiveState(true);
34718 panel.setSize(this.box.width, this.box.height);
34720 this.fireEvent("panelactivated", this, panel);
34721 this.fireEvent("invalidated");
34725 * Show the specified panel.
34726 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34727 * @return {Roo.ContentPanel} The shown panel or null
34729 showPanel : function(panel){
34730 panel = this.getPanel(panel);
34732 this.setActivePanel(panel);
34738 * Get the active panel for this region.
34739 * @return {Roo.ContentPanel} The active panel or null
34741 getActivePanel : function(){
34742 return this.activePanel;
34746 * Add the passed ContentPanel(s)
34747 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34748 * @return {Roo.ContentPanel} The panel added (if only one was added)
34750 add : function(panel){
34751 if(arguments.length > 1){
34752 for(var i = 0, len = arguments.length; i < len; i++) {
34753 this.add(arguments[i]);
34757 if(this.hasPanel(panel)){
34758 this.showPanel(panel);
34761 var el = panel.getEl();
34762 if(el.dom.parentNode != this.mgr.el.dom){
34763 this.mgr.el.dom.appendChild(el.dom);
34765 if(panel.setRegion){
34766 panel.setRegion(this);
34768 this.panels.add(panel);
34769 el.setStyle("position", "absolute");
34770 if(!panel.background){
34771 this.setActivePanel(panel);
34772 if(this.config.initialSize && this.panels.getCount()==1){
34773 this.resizeTo(this.config.initialSize);
34776 this.fireEvent("paneladded", this, panel);
34781 * Returns true if the panel is in this region.
34782 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34783 * @return {Boolean}
34785 hasPanel : function(panel){
34786 if(typeof panel == "object"){ // must be panel obj
34787 panel = panel.getId();
34789 return this.getPanel(panel) ? true : false;
34793 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34794 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34795 * @param {Boolean} preservePanel Overrides the config preservePanel option
34796 * @return {Roo.ContentPanel} The panel that was removed
34798 remove : function(panel, preservePanel){
34799 panel = this.getPanel(panel);
34804 this.fireEvent("beforeremove", this, panel, e);
34805 if(e.cancel === true){
34808 var panelId = panel.getId();
34809 this.panels.removeKey(panelId);
34814 * Returns the panel specified or null if it's not in this region.
34815 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34816 * @return {Roo.ContentPanel}
34818 getPanel : function(id){
34819 if(typeof id == "object"){ // must be panel obj
34822 return this.panels.get(id);
34826 * Returns this regions position (north/south/east/west/center).
34829 getPosition: function(){
34830 return this.position;
34834 * Ext JS Library 1.1.1
34835 * Copyright(c) 2006-2007, Ext JS, LLC.
34837 * Originally Released Under LGPL - original licence link has changed is not relivant.
34840 * <script type="text/javascript">
34844 * @class Roo.bootstrap.layout.Region
34845 * @extends Roo.bootstrap.layout.Basic
34846 * This class represents a region in a layout manager.
34848 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34849 * @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})
34850 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34851 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34852 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34853 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34854 * @cfg {String} title The title for the region (overrides panel titles)
34855 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34856 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34857 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34858 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34859 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34860 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34861 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34862 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34863 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34864 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34866 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34867 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34868 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34869 * @cfg {Number} width For East/West panels
34870 * @cfg {Number} height For North/South panels
34871 * @cfg {Boolean} split To show the splitter
34872 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34874 * @cfg {string} cls Extra CSS classes to add to region
34876 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34877 * @cfg {string} region the region that it inhabits..
34880 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34881 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34883 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34884 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34885 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34887 Roo.bootstrap.layout.Region = function(config)
34889 this.applyConfig(config);
34891 var mgr = config.mgr;
34892 var pos = config.region;
34893 config.skipConfig = true;
34894 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34897 this.onRender(mgr.el);
34900 this.visible = true;
34901 this.collapsed = false;
34902 this.unrendered_panels = [];
34905 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34907 position: '', // set by wrapper (eg. north/south etc..)
34908 unrendered_panels : null, // unrendered panels.
34909 createBody : function(){
34910 /** This region's body element
34911 * @type Roo.Element */
34912 this.bodyEl = this.el.createChild({
34914 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34918 onRender: function(ctr, pos)
34920 var dh = Roo.DomHelper;
34921 /** This region's container element
34922 * @type Roo.Element */
34923 this.el = dh.append(ctr.dom, {
34925 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34927 /** This region's title element
34928 * @type Roo.Element */
34930 this.titleEl = dh.append(this.el.dom,
34933 unselectable: "on",
34934 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34936 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34937 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34940 this.titleEl.enableDisplayMode();
34941 /** This region's title text element
34942 * @type HTMLElement */
34943 this.titleTextEl = this.titleEl.dom.firstChild;
34944 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34946 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34947 this.closeBtn.enableDisplayMode();
34948 this.closeBtn.on("click", this.closeClicked, this);
34949 this.closeBtn.hide();
34951 this.createBody(this.config);
34952 if(this.config.hideWhenEmpty){
34954 this.on("paneladded", this.validateVisibility, this);
34955 this.on("panelremoved", this.validateVisibility, this);
34957 if(this.autoScroll){
34958 this.bodyEl.setStyle("overflow", "auto");
34960 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34962 //if(c.titlebar !== false){
34963 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34964 this.titleEl.hide();
34966 this.titleEl.show();
34967 if(this.config.title){
34968 this.titleTextEl.innerHTML = this.config.title;
34972 if(this.config.collapsed){
34973 this.collapse(true);
34975 if(this.config.hidden){
34979 if (this.unrendered_panels && this.unrendered_panels.length) {
34980 for (var i =0;i< this.unrendered_panels.length; i++) {
34981 this.add(this.unrendered_panels[i]);
34983 this.unrendered_panels = null;
34989 applyConfig : function(c)
34992 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34993 var dh = Roo.DomHelper;
34994 if(c.titlebar !== false){
34995 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34996 this.collapseBtn.on("click", this.collapse, this);
34997 this.collapseBtn.enableDisplayMode();
34999 if(c.showPin === true || this.showPin){
35000 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35001 this.stickBtn.enableDisplayMode();
35002 this.stickBtn.on("click", this.expand, this);
35003 this.stickBtn.hide();
35008 /** This region's collapsed element
35009 * @type Roo.Element */
35012 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35013 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35016 if(c.floatable !== false){
35017 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35018 this.collapsedEl.on("click", this.collapseClick, this);
35021 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35022 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35023 id: "message", unselectable: "on", style:{"float":"left"}});
35024 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35026 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35027 this.expandBtn.on("click", this.expand, this);
35031 if(this.collapseBtn){
35032 this.collapseBtn.setVisible(c.collapsible == true);
35035 this.cmargins = c.cmargins || this.cmargins ||
35036 (this.position == "west" || this.position == "east" ?
35037 {top: 0, left: 2, right:2, bottom: 0} :
35038 {top: 2, left: 0, right:0, bottom: 2});
35040 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35043 this.bottomTabs = c.tabPosition != "top";
35045 this.autoScroll = c.autoScroll || false;
35050 this.duration = c.duration || .30;
35051 this.slideDuration = c.slideDuration || .45;
35056 * Returns true if this region is currently visible.
35057 * @return {Boolean}
35059 isVisible : function(){
35060 return this.visible;
35064 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35065 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35067 //setCollapsedTitle : function(title){
35068 // title = title || " ";
35069 // if(this.collapsedTitleTextEl){
35070 // this.collapsedTitleTextEl.innerHTML = title;
35074 getBox : function(){
35076 // if(!this.collapsed){
35077 b = this.el.getBox(false, true);
35079 // b = this.collapsedEl.getBox(false, true);
35084 getMargins : function(){
35085 return this.margins;
35086 //return this.collapsed ? this.cmargins : this.margins;
35089 highlight : function(){
35090 this.el.addClass("x-layout-panel-dragover");
35093 unhighlight : function(){
35094 this.el.removeClass("x-layout-panel-dragover");
35097 updateBox : function(box)
35099 if (!this.bodyEl) {
35100 return; // not rendered yet..
35104 if(!this.collapsed){
35105 this.el.dom.style.left = box.x + "px";
35106 this.el.dom.style.top = box.y + "px";
35107 this.updateBody(box.width, box.height);
35109 this.collapsedEl.dom.style.left = box.x + "px";
35110 this.collapsedEl.dom.style.top = box.y + "px";
35111 this.collapsedEl.setSize(box.width, box.height);
35114 this.tabs.autoSizeTabs();
35118 updateBody : function(w, h)
35121 this.el.setWidth(w);
35122 w -= this.el.getBorderWidth("rl");
35123 if(this.config.adjustments){
35124 w += this.config.adjustments[0];
35127 if(h !== null && h > 0){
35128 this.el.setHeight(h);
35129 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35130 h -= this.el.getBorderWidth("tb");
35131 if(this.config.adjustments){
35132 h += this.config.adjustments[1];
35134 this.bodyEl.setHeight(h);
35136 h = this.tabs.syncHeight(h);
35139 if(this.panelSize){
35140 w = w !== null ? w : this.panelSize.width;
35141 h = h !== null ? h : this.panelSize.height;
35143 if(this.activePanel){
35144 var el = this.activePanel.getEl();
35145 w = w !== null ? w : el.getWidth();
35146 h = h !== null ? h : el.getHeight();
35147 this.panelSize = {width: w, height: h};
35148 this.activePanel.setSize(w, h);
35150 if(Roo.isIE && this.tabs){
35151 this.tabs.el.repaint();
35156 * Returns the container element for this region.
35157 * @return {Roo.Element}
35159 getEl : function(){
35164 * Hides this region.
35167 //if(!this.collapsed){
35168 this.el.dom.style.left = "-2000px";
35171 // this.collapsedEl.dom.style.left = "-2000px";
35172 // this.collapsedEl.hide();
35174 this.visible = false;
35175 this.fireEvent("visibilitychange", this, false);
35179 * Shows this region if it was previously hidden.
35182 //if(!this.collapsed){
35185 // this.collapsedEl.show();
35187 this.visible = true;
35188 this.fireEvent("visibilitychange", this, true);
35191 closeClicked : function(){
35192 if(this.activePanel){
35193 this.remove(this.activePanel);
35197 collapseClick : function(e){
35199 e.stopPropagation();
35202 e.stopPropagation();
35208 * Collapses this region.
35209 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35212 collapse : function(skipAnim, skipCheck = false){
35213 if(this.collapsed) {
35217 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35219 this.collapsed = true;
35221 this.split.el.hide();
35223 if(this.config.animate && skipAnim !== true){
35224 this.fireEvent("invalidated", this);
35225 this.animateCollapse();
35227 this.el.setLocation(-20000,-20000);
35229 this.collapsedEl.show();
35230 this.fireEvent("collapsed", this);
35231 this.fireEvent("invalidated", this);
35237 animateCollapse : function(){
35242 * Expands this region if it was previously collapsed.
35243 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35244 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35247 expand : function(e, skipAnim){
35249 e.stopPropagation();
35251 if(!this.collapsed || this.el.hasActiveFx()) {
35255 this.afterSlideIn();
35258 this.collapsed = false;
35259 if(this.config.animate && skipAnim !== true){
35260 this.animateExpand();
35264 this.split.el.show();
35266 this.collapsedEl.setLocation(-2000,-2000);
35267 this.collapsedEl.hide();
35268 this.fireEvent("invalidated", this);
35269 this.fireEvent("expanded", this);
35273 animateExpand : function(){
35277 initTabs : function()
35279 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35281 var ts = new Roo.bootstrap.panel.Tabs({
35282 el: this.bodyEl.dom,
35283 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35284 disableTooltips: this.config.disableTabTips,
35285 toolbar : this.config.toolbar
35288 if(this.config.hideTabs){
35289 ts.stripWrap.setDisplayed(false);
35292 ts.resizeTabs = this.config.resizeTabs === true;
35293 ts.minTabWidth = this.config.minTabWidth || 40;
35294 ts.maxTabWidth = this.config.maxTabWidth || 250;
35295 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35296 ts.monitorResize = false;
35297 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35298 ts.bodyEl.addClass('roo-layout-tabs-body');
35299 this.panels.each(this.initPanelAsTab, this);
35302 initPanelAsTab : function(panel){
35303 var ti = this.tabs.addTab(
35307 this.config.closeOnTab && panel.isClosable(),
35310 if(panel.tabTip !== undefined){
35311 ti.setTooltip(panel.tabTip);
35313 ti.on("activate", function(){
35314 this.setActivePanel(panel);
35317 if(this.config.closeOnTab){
35318 ti.on("beforeclose", function(t, e){
35320 this.remove(panel);
35324 panel.tabItem = ti;
35329 updatePanelTitle : function(panel, title)
35331 if(this.activePanel == panel){
35332 this.updateTitle(title);
35335 var ti = this.tabs.getTab(panel.getEl().id);
35337 if(panel.tabTip !== undefined){
35338 ti.setTooltip(panel.tabTip);
35343 updateTitle : function(title){
35344 if(this.titleTextEl && !this.config.title){
35345 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35349 setActivePanel : function(panel)
35351 panel = this.getPanel(panel);
35352 if(this.activePanel && this.activePanel != panel){
35353 this.activePanel.setActiveState(false);
35355 this.activePanel = panel;
35356 panel.setActiveState(true);
35357 if(this.panelSize){
35358 panel.setSize(this.panelSize.width, this.panelSize.height);
35361 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35363 this.updateTitle(panel.getTitle());
35365 this.fireEvent("invalidated", this);
35367 this.fireEvent("panelactivated", this, panel);
35371 * Shows the specified panel.
35372 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35373 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35375 showPanel : function(panel)
35377 panel = this.getPanel(panel);
35380 var tab = this.tabs.getTab(panel.getEl().id);
35381 if(tab.isHidden()){
35382 this.tabs.unhideTab(tab.id);
35386 this.setActivePanel(panel);
35393 * Get the active panel for this region.
35394 * @return {Roo.ContentPanel} The active panel or null
35396 getActivePanel : function(){
35397 return this.activePanel;
35400 validateVisibility : function(){
35401 if(this.panels.getCount() < 1){
35402 this.updateTitle(" ");
35403 this.closeBtn.hide();
35406 if(!this.isVisible()){
35413 * Adds the passed ContentPanel(s) to this region.
35414 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35415 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35417 add : function(panel)
35419 if(arguments.length > 1){
35420 for(var i = 0, len = arguments.length; i < len; i++) {
35421 this.add(arguments[i]);
35426 // if we have not been rendered yet, then we can not really do much of this..
35427 if (!this.bodyEl) {
35428 this.unrendered_panels.push(panel);
35435 if(this.hasPanel(panel)){
35436 this.showPanel(panel);
35439 panel.setRegion(this);
35440 this.panels.add(panel);
35441 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35442 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35443 // and hide them... ???
35444 this.bodyEl.dom.appendChild(panel.getEl().dom);
35445 if(panel.background !== true){
35446 this.setActivePanel(panel);
35448 this.fireEvent("paneladded", this, panel);
35455 this.initPanelAsTab(panel);
35459 if(panel.background !== true){
35460 this.tabs.activate(panel.getEl().id);
35462 this.fireEvent("paneladded", this, panel);
35467 * Hides the tab for the specified panel.
35468 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35470 hidePanel : function(panel){
35471 if(this.tabs && (panel = this.getPanel(panel))){
35472 this.tabs.hideTab(panel.getEl().id);
35477 * Unhides the tab for a previously hidden panel.
35478 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35480 unhidePanel : function(panel){
35481 if(this.tabs && (panel = this.getPanel(panel))){
35482 this.tabs.unhideTab(panel.getEl().id);
35486 clearPanels : function(){
35487 while(this.panels.getCount() > 0){
35488 this.remove(this.panels.first());
35493 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35494 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35495 * @param {Boolean} preservePanel Overrides the config preservePanel option
35496 * @return {Roo.ContentPanel} The panel that was removed
35498 remove : function(panel, preservePanel)
35500 panel = this.getPanel(panel);
35505 this.fireEvent("beforeremove", this, panel, e);
35506 if(e.cancel === true){
35509 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35510 var panelId = panel.getId();
35511 this.panels.removeKey(panelId);
35513 document.body.appendChild(panel.getEl().dom);
35516 this.tabs.removeTab(panel.getEl().id);
35517 }else if (!preservePanel){
35518 this.bodyEl.dom.removeChild(panel.getEl().dom);
35520 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35521 var p = this.panels.first();
35522 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35523 tempEl.appendChild(p.getEl().dom);
35524 this.bodyEl.update("");
35525 this.bodyEl.dom.appendChild(p.getEl().dom);
35527 this.updateTitle(p.getTitle());
35529 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35530 this.setActivePanel(p);
35532 panel.setRegion(null);
35533 if(this.activePanel == panel){
35534 this.activePanel = null;
35536 if(this.config.autoDestroy !== false && preservePanel !== true){
35537 try{panel.destroy();}catch(e){}
35539 this.fireEvent("panelremoved", this, panel);
35544 * Returns the TabPanel component used by this region
35545 * @return {Roo.TabPanel}
35547 getTabs : function(){
35551 createTool : function(parentEl, className){
35552 var btn = Roo.DomHelper.append(parentEl, {
35554 cls: "x-layout-tools-button",
35557 cls: "roo-layout-tools-button-inner " + className,
35561 btn.addClassOnOver("roo-layout-tools-button-over");
35566 * Ext JS Library 1.1.1
35567 * Copyright(c) 2006-2007, Ext JS, LLC.
35569 * Originally Released Under LGPL - original licence link has changed is not relivant.
35572 * <script type="text/javascript">
35578 * @class Roo.SplitLayoutRegion
35579 * @extends Roo.LayoutRegion
35580 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35582 Roo.bootstrap.layout.Split = function(config){
35583 this.cursor = config.cursor;
35584 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35587 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35589 splitTip : "Drag to resize.",
35590 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35591 useSplitTips : false,
35593 applyConfig : function(config){
35594 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35597 onRender : function(ctr,pos) {
35599 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35600 if(!this.config.split){
35605 var splitEl = Roo.DomHelper.append(ctr.dom, {
35607 id: this.el.id + "-split",
35608 cls: "roo-layout-split roo-layout-split-"+this.position,
35611 /** The SplitBar for this region
35612 * @type Roo.SplitBar */
35613 // does not exist yet...
35614 Roo.log([this.position, this.orientation]);
35616 this.split = new Roo.bootstrap.SplitBar({
35617 dragElement : splitEl,
35618 resizingElement: this.el,
35619 orientation : this.orientation
35622 this.split.on("moved", this.onSplitMove, this);
35623 this.split.useShim = this.config.useShim === true;
35624 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35625 if(this.useSplitTips){
35626 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35628 //if(config.collapsible){
35629 // this.split.el.on("dblclick", this.collapse, this);
35632 if(typeof this.config.minSize != "undefined"){
35633 this.split.minSize = this.config.minSize;
35635 if(typeof this.config.maxSize != "undefined"){
35636 this.split.maxSize = this.config.maxSize;
35638 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35639 this.hideSplitter();
35644 getHMaxSize : function(){
35645 var cmax = this.config.maxSize || 10000;
35646 var center = this.mgr.getRegion("center");
35647 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35650 getVMaxSize : function(){
35651 var cmax = this.config.maxSize || 10000;
35652 var center = this.mgr.getRegion("center");
35653 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35656 onSplitMove : function(split, newSize){
35657 this.fireEvent("resized", this, newSize);
35661 * Returns the {@link Roo.SplitBar} for this region.
35662 * @return {Roo.SplitBar}
35664 getSplitBar : function(){
35669 this.hideSplitter();
35670 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35673 hideSplitter : function(){
35675 this.split.el.setLocation(-2000,-2000);
35676 this.split.el.hide();
35682 this.split.el.show();
35684 Roo.bootstrap.layout.Split.superclass.show.call(this);
35687 beforeSlide: function(){
35688 if(Roo.isGecko){// firefox overflow auto bug workaround
35689 this.bodyEl.clip();
35691 this.tabs.bodyEl.clip();
35693 if(this.activePanel){
35694 this.activePanel.getEl().clip();
35696 if(this.activePanel.beforeSlide){
35697 this.activePanel.beforeSlide();
35703 afterSlide : function(){
35704 if(Roo.isGecko){// firefox overflow auto bug workaround
35705 this.bodyEl.unclip();
35707 this.tabs.bodyEl.unclip();
35709 if(this.activePanel){
35710 this.activePanel.getEl().unclip();
35711 if(this.activePanel.afterSlide){
35712 this.activePanel.afterSlide();
35718 initAutoHide : function(){
35719 if(this.autoHide !== false){
35720 if(!this.autoHideHd){
35721 var st = new Roo.util.DelayedTask(this.slideIn, this);
35722 this.autoHideHd = {
35723 "mouseout": function(e){
35724 if(!e.within(this.el, true)){
35728 "mouseover" : function(e){
35734 this.el.on(this.autoHideHd);
35738 clearAutoHide : function(){
35739 if(this.autoHide !== false){
35740 this.el.un("mouseout", this.autoHideHd.mouseout);
35741 this.el.un("mouseover", this.autoHideHd.mouseover);
35745 clearMonitor : function(){
35746 Roo.get(document).un("click", this.slideInIf, this);
35749 // these names are backwards but not changed for compat
35750 slideOut : function(){
35751 if(this.isSlid || this.el.hasActiveFx()){
35754 this.isSlid = true;
35755 if(this.collapseBtn){
35756 this.collapseBtn.hide();
35758 this.closeBtnState = this.closeBtn.getStyle('display');
35759 this.closeBtn.hide();
35761 this.stickBtn.show();
35764 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35765 this.beforeSlide();
35766 this.el.setStyle("z-index", 10001);
35767 this.el.slideIn(this.getSlideAnchor(), {
35768 callback: function(){
35770 this.initAutoHide();
35771 Roo.get(document).on("click", this.slideInIf, this);
35772 this.fireEvent("slideshow", this);
35779 afterSlideIn : function(){
35780 this.clearAutoHide();
35781 this.isSlid = false;
35782 this.clearMonitor();
35783 this.el.setStyle("z-index", "");
35784 if(this.collapseBtn){
35785 this.collapseBtn.show();
35787 this.closeBtn.setStyle('display', this.closeBtnState);
35789 this.stickBtn.hide();
35791 this.fireEvent("slidehide", this);
35794 slideIn : function(cb){
35795 if(!this.isSlid || this.el.hasActiveFx()){
35799 this.isSlid = false;
35800 this.beforeSlide();
35801 this.el.slideOut(this.getSlideAnchor(), {
35802 callback: function(){
35803 this.el.setLeftTop(-10000, -10000);
35805 this.afterSlideIn();
35813 slideInIf : function(e){
35814 if(!e.within(this.el)){
35819 animateCollapse : function(){
35820 this.beforeSlide();
35821 this.el.setStyle("z-index", 20000);
35822 var anchor = this.getSlideAnchor();
35823 this.el.slideOut(anchor, {
35824 callback : function(){
35825 this.el.setStyle("z-index", "");
35826 this.collapsedEl.slideIn(anchor, {duration:.3});
35828 this.el.setLocation(-10000,-10000);
35830 this.fireEvent("collapsed", this);
35837 animateExpand : function(){
35838 this.beforeSlide();
35839 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35840 this.el.setStyle("z-index", 20000);
35841 this.collapsedEl.hide({
35844 this.el.slideIn(this.getSlideAnchor(), {
35845 callback : function(){
35846 this.el.setStyle("z-index", "");
35849 this.split.el.show();
35851 this.fireEvent("invalidated", this);
35852 this.fireEvent("expanded", this);
35880 getAnchor : function(){
35881 return this.anchors[this.position];
35884 getCollapseAnchor : function(){
35885 return this.canchors[this.position];
35888 getSlideAnchor : function(){
35889 return this.sanchors[this.position];
35892 getAlignAdj : function(){
35893 var cm = this.cmargins;
35894 switch(this.position){
35910 getExpandAdj : function(){
35911 var c = this.collapsedEl, cm = this.cmargins;
35912 switch(this.position){
35914 return [-(cm.right+c.getWidth()+cm.left), 0];
35917 return [cm.right+c.getWidth()+cm.left, 0];
35920 return [0, -(cm.top+cm.bottom+c.getHeight())];
35923 return [0, cm.top+cm.bottom+c.getHeight()];
35929 * Ext JS Library 1.1.1
35930 * Copyright(c) 2006-2007, Ext JS, LLC.
35932 * Originally Released Under LGPL - original licence link has changed is not relivant.
35935 * <script type="text/javascript">
35938 * These classes are private internal classes
35940 Roo.bootstrap.layout.Center = function(config){
35941 config.region = "center";
35942 Roo.bootstrap.layout.Region.call(this, config);
35943 this.visible = true;
35944 this.minWidth = config.minWidth || 20;
35945 this.minHeight = config.minHeight || 20;
35948 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35950 // center panel can't be hidden
35954 // center panel can't be hidden
35957 getMinWidth: function(){
35958 return this.minWidth;
35961 getMinHeight: function(){
35962 return this.minHeight;
35975 Roo.bootstrap.layout.North = function(config)
35977 config.region = 'north';
35978 config.cursor = 'n-resize';
35980 Roo.bootstrap.layout.Split.call(this, config);
35984 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35985 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35986 this.split.el.addClass("roo-layout-split-v");
35988 var size = config.initialSize || config.height;
35989 if(typeof size != "undefined"){
35990 this.el.setHeight(size);
35993 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35995 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35999 getBox : function(){
36000 if(this.collapsed){
36001 return this.collapsedEl.getBox();
36003 var box = this.el.getBox();
36005 box.height += this.split.el.getHeight();
36010 updateBox : function(box){
36011 if(this.split && !this.collapsed){
36012 box.height -= this.split.el.getHeight();
36013 this.split.el.setLeft(box.x);
36014 this.split.el.setTop(box.y+box.height);
36015 this.split.el.setWidth(box.width);
36017 if(this.collapsed){
36018 this.updateBody(box.width, null);
36020 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36028 Roo.bootstrap.layout.South = function(config){
36029 config.region = 'south';
36030 config.cursor = 's-resize';
36031 Roo.bootstrap.layout.Split.call(this, config);
36033 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36034 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36035 this.split.el.addClass("roo-layout-split-v");
36037 var size = config.initialSize || config.height;
36038 if(typeof size != "undefined"){
36039 this.el.setHeight(size);
36043 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36044 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36045 getBox : function(){
36046 if(this.collapsed){
36047 return this.collapsedEl.getBox();
36049 var box = this.el.getBox();
36051 var sh = this.split.el.getHeight();
36058 updateBox : function(box){
36059 if(this.split && !this.collapsed){
36060 var sh = this.split.el.getHeight();
36063 this.split.el.setLeft(box.x);
36064 this.split.el.setTop(box.y-sh);
36065 this.split.el.setWidth(box.width);
36067 if(this.collapsed){
36068 this.updateBody(box.width, null);
36070 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36074 Roo.bootstrap.layout.East = function(config){
36075 config.region = "east";
36076 config.cursor = "e-resize";
36077 Roo.bootstrap.layout.Split.call(this, config);
36079 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36080 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36081 this.split.el.addClass("roo-layout-split-h");
36083 var size = config.initialSize || config.width;
36084 if(typeof size != "undefined"){
36085 this.el.setWidth(size);
36088 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36089 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36090 getBox : function(){
36091 if(this.collapsed){
36092 return this.collapsedEl.getBox();
36094 var box = this.el.getBox();
36096 var sw = this.split.el.getWidth();
36103 updateBox : function(box){
36104 if(this.split && !this.collapsed){
36105 var sw = this.split.el.getWidth();
36107 this.split.el.setLeft(box.x);
36108 this.split.el.setTop(box.y);
36109 this.split.el.setHeight(box.height);
36112 if(this.collapsed){
36113 this.updateBody(null, box.height);
36115 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36119 Roo.bootstrap.layout.West = function(config){
36120 config.region = "west";
36121 config.cursor = "w-resize";
36123 Roo.bootstrap.layout.Split.call(this, config);
36125 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36126 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36127 this.split.el.addClass("roo-layout-split-h");
36131 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36132 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36134 onRender: function(ctr, pos)
36136 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36137 var size = this.config.initialSize || this.config.width;
36138 if(typeof size != "undefined"){
36139 this.el.setWidth(size);
36143 getBox : function(){
36144 if(this.collapsed){
36145 return this.collapsedEl.getBox();
36147 var box = this.el.getBox();
36149 box.width += this.split.el.getWidth();
36154 updateBox : function(box){
36155 if(this.split && !this.collapsed){
36156 var sw = this.split.el.getWidth();
36158 this.split.el.setLeft(box.x+box.width);
36159 this.split.el.setTop(box.y);
36160 this.split.el.setHeight(box.height);
36162 if(this.collapsed){
36163 this.updateBody(null, box.height);
36165 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36168 Roo.namespace("Roo.bootstrap.panel");/*
36170 * Ext JS Library 1.1.1
36171 * Copyright(c) 2006-2007, Ext JS, LLC.
36173 * Originally Released Under LGPL - original licence link has changed is not relivant.
36176 * <script type="text/javascript">
36179 * @class Roo.ContentPanel
36180 * @extends Roo.util.Observable
36181 * A basic ContentPanel element.
36182 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36183 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36184 * @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
36185 * @cfg {Boolean} closable True if the panel can be closed/removed
36186 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36187 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36188 * @cfg {Toolbar} toolbar A toolbar for this panel
36189 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36190 * @cfg {String} title The title for this panel
36191 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36192 * @cfg {String} url Calls {@link #setUrl} with this value
36193 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36194 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36195 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36196 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36197 * @cfg {Boolean} badges render the badges
36200 * Create a new ContentPanel.
36201 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36202 * @param {String/Object} config A string to set only the title or a config object
36203 * @param {String} content (optional) Set the HTML content for this panel
36204 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36206 Roo.bootstrap.panel.Content = function( config){
36208 this.tpl = config.tpl || false;
36210 var el = config.el;
36211 var content = config.content;
36213 if(config.autoCreate){ // xtype is available if this is called from factory
36216 this.el = Roo.get(el);
36217 if(!this.el && config && config.autoCreate){
36218 if(typeof config.autoCreate == "object"){
36219 if(!config.autoCreate.id){
36220 config.autoCreate.id = config.id||el;
36222 this.el = Roo.DomHelper.append(document.body,
36223 config.autoCreate, true);
36225 var elcfg = { tag: "div",
36226 cls: "roo-layout-inactive-content",
36230 elcfg.html = config.html;
36234 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36237 this.closable = false;
36238 this.loaded = false;
36239 this.active = false;
36242 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36244 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36246 this.wrapEl = this.el; //this.el.wrap();
36248 if (config.toolbar.items) {
36249 ti = config.toolbar.items ;
36250 delete config.toolbar.items ;
36254 this.toolbar.render(this.wrapEl, 'before');
36255 for(var i =0;i < ti.length;i++) {
36256 // Roo.log(['add child', items[i]]);
36257 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36259 this.toolbar.items = nitems;
36260 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36261 delete config.toolbar;
36265 // xtype created footer. - not sure if will work as we normally have to render first..
36266 if (this.footer && !this.footer.el && this.footer.xtype) {
36267 if (!this.wrapEl) {
36268 this.wrapEl = this.el.wrap();
36271 this.footer.container = this.wrapEl.createChild();
36273 this.footer = Roo.factory(this.footer, Roo);
36278 if(typeof config == "string"){
36279 this.title = config;
36281 Roo.apply(this, config);
36285 this.resizeEl = Roo.get(this.resizeEl, true);
36287 this.resizeEl = this.el;
36289 // handle view.xtype
36297 * Fires when this panel is activated.
36298 * @param {Roo.ContentPanel} this
36302 * @event deactivate
36303 * Fires when this panel is activated.
36304 * @param {Roo.ContentPanel} this
36306 "deactivate" : true,
36310 * Fires when this panel is resized if fitToFrame is true.
36311 * @param {Roo.ContentPanel} this
36312 * @param {Number} width The width after any component adjustments
36313 * @param {Number} height The height after any component adjustments
36319 * Fires when this tab is created
36320 * @param {Roo.ContentPanel} this
36331 if(this.autoScroll){
36332 this.resizeEl.setStyle("overflow", "auto");
36334 // fix randome scrolling
36335 //this.el.on('scroll', function() {
36336 // Roo.log('fix random scolling');
36337 // this.scrollTo('top',0);
36340 content = content || this.content;
36342 this.setContent(content);
36344 if(config && config.url){
36345 this.setUrl(this.url, this.params, this.loadOnce);
36350 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36352 if (this.view && typeof(this.view.xtype) != 'undefined') {
36353 this.view.el = this.el.appendChild(document.createElement("div"));
36354 this.view = Roo.factory(this.view);
36355 this.view.render && this.view.render(false, '');
36359 this.fireEvent('render', this);
36362 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36366 setRegion : function(region){
36367 this.region = region;
36368 this.setActiveClass(region && !this.background);
36372 setActiveClass: function(state)
36375 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36376 this.el.setStyle('position','relative');
36378 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36379 this.el.setStyle('position', 'absolute');
36384 * Returns the toolbar for this Panel if one was configured.
36385 * @return {Roo.Toolbar}
36387 getToolbar : function(){
36388 return this.toolbar;
36391 setActiveState : function(active)
36393 this.active = active;
36394 this.setActiveClass(active);
36396 this.fireEvent("deactivate", this);
36398 this.fireEvent("activate", this);
36402 * Updates this panel's element
36403 * @param {String} content The new content
36404 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36406 setContent : function(content, loadScripts){
36407 this.el.update(content, loadScripts);
36410 ignoreResize : function(w, h){
36411 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36414 this.lastSize = {width: w, height: h};
36419 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36420 * @return {Roo.UpdateManager} The UpdateManager
36422 getUpdateManager : function(){
36423 return this.el.getUpdateManager();
36426 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36427 * @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:
36430 url: "your-url.php",
36431 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36432 callback: yourFunction,
36433 scope: yourObject, //(optional scope)
36436 text: "Loading...",
36441 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36442 * 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.
36443 * @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}
36444 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36445 * @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.
36446 * @return {Roo.ContentPanel} this
36449 var um = this.el.getUpdateManager();
36450 um.update.apply(um, arguments);
36456 * 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.
36457 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36458 * @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)
36459 * @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)
36460 * @return {Roo.UpdateManager} The UpdateManager
36462 setUrl : function(url, params, loadOnce){
36463 if(this.refreshDelegate){
36464 this.removeListener("activate", this.refreshDelegate);
36466 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36467 this.on("activate", this.refreshDelegate);
36468 return this.el.getUpdateManager();
36471 _handleRefresh : function(url, params, loadOnce){
36472 if(!loadOnce || !this.loaded){
36473 var updater = this.el.getUpdateManager();
36474 updater.update(url, params, this._setLoaded.createDelegate(this));
36478 _setLoaded : function(){
36479 this.loaded = true;
36483 * Returns this panel's id
36486 getId : function(){
36491 * Returns this panel's element - used by regiosn to add.
36492 * @return {Roo.Element}
36494 getEl : function(){
36495 return this.wrapEl || this.el;
36500 adjustForComponents : function(width, height)
36502 //Roo.log('adjustForComponents ');
36503 if(this.resizeEl != this.el){
36504 width -= this.el.getFrameWidth('lr');
36505 height -= this.el.getFrameWidth('tb');
36508 var te = this.toolbar.getEl();
36509 te.setWidth(width);
36510 height -= te.getHeight();
36513 var te = this.footer.getEl();
36514 te.setWidth(width);
36515 height -= te.getHeight();
36519 if(this.adjustments){
36520 width += this.adjustments[0];
36521 height += this.adjustments[1];
36523 return {"width": width, "height": height};
36526 setSize : function(width, height){
36527 if(this.fitToFrame && !this.ignoreResize(width, height)){
36528 if(this.fitContainer && this.resizeEl != this.el){
36529 this.el.setSize(width, height);
36531 var size = this.adjustForComponents(width, height);
36532 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36533 this.fireEvent('resize', this, size.width, size.height);
36538 * Returns this panel's title
36541 getTitle : function(){
36543 if (typeof(this.title) != 'object') {
36548 for (var k in this.title) {
36549 if (!this.title.hasOwnProperty(k)) {
36553 if (k.indexOf('-') >= 0) {
36554 var s = k.split('-');
36555 for (var i = 0; i<s.length; i++) {
36556 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36559 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36566 * Set this panel's title
36567 * @param {String} title
36569 setTitle : function(title){
36570 this.title = title;
36572 this.region.updatePanelTitle(this, title);
36577 * Returns true is this panel was configured to be closable
36578 * @return {Boolean}
36580 isClosable : function(){
36581 return this.closable;
36584 beforeSlide : function(){
36586 this.resizeEl.clip();
36589 afterSlide : function(){
36591 this.resizeEl.unclip();
36595 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36596 * Will fail silently if the {@link #setUrl} method has not been called.
36597 * This does not activate the panel, just updates its content.
36599 refresh : function(){
36600 if(this.refreshDelegate){
36601 this.loaded = false;
36602 this.refreshDelegate();
36607 * Destroys this panel
36609 destroy : function(){
36610 this.el.removeAllListeners();
36611 var tempEl = document.createElement("span");
36612 tempEl.appendChild(this.el.dom);
36613 tempEl.innerHTML = "";
36619 * form - if the content panel contains a form - this is a reference to it.
36620 * @type {Roo.form.Form}
36624 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36625 * This contains a reference to it.
36631 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36641 * @param {Object} cfg Xtype definition of item to add.
36645 getChildContainer: function () {
36646 return this.getEl();
36651 var ret = new Roo.factory(cfg);
36656 if (cfg.xtype.match(/^Form$/)) {
36659 //if (this.footer) {
36660 // el = this.footer.container.insertSibling(false, 'before');
36662 el = this.el.createChild();
36665 this.form = new Roo.form.Form(cfg);
36668 if ( this.form.allItems.length) {
36669 this.form.render(el.dom);
36673 // should only have one of theses..
36674 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36675 // views.. should not be just added - used named prop 'view''
36677 cfg.el = this.el.appendChild(document.createElement("div"));
36680 var ret = new Roo.factory(cfg);
36682 ret.render && ret.render(false, ''); // render blank..
36692 * @class Roo.bootstrap.panel.Grid
36693 * @extends Roo.bootstrap.panel.Content
36695 * Create a new GridPanel.
36696 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36697 * @param {Object} config A the config object
36703 Roo.bootstrap.panel.Grid = function(config)
36707 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36708 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36710 config.el = this.wrapper;
36711 //this.el = this.wrapper;
36713 if (config.container) {
36714 // ctor'ed from a Border/panel.grid
36717 this.wrapper.setStyle("overflow", "hidden");
36718 this.wrapper.addClass('roo-grid-container');
36723 if(config.toolbar){
36724 var tool_el = this.wrapper.createChild();
36725 this.toolbar = Roo.factory(config.toolbar);
36727 if (config.toolbar.items) {
36728 ti = config.toolbar.items ;
36729 delete config.toolbar.items ;
36733 this.toolbar.render(tool_el);
36734 for(var i =0;i < ti.length;i++) {
36735 // Roo.log(['add child', items[i]]);
36736 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36738 this.toolbar.items = nitems;
36740 delete config.toolbar;
36743 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36744 config.grid.scrollBody = true;;
36745 config.grid.monitorWindowResize = false; // turn off autosizing
36746 config.grid.autoHeight = false;
36747 config.grid.autoWidth = false;
36749 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36751 if (config.background) {
36752 // render grid on panel activation (if panel background)
36753 this.on('activate', function(gp) {
36754 if (!gp.grid.rendered) {
36755 gp.grid.render(this.wrapper);
36756 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36761 this.grid.render(this.wrapper);
36762 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36765 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36766 // ??? needed ??? config.el = this.wrapper;
36771 // xtype created footer. - not sure if will work as we normally have to render first..
36772 if (this.footer && !this.footer.el && this.footer.xtype) {
36774 var ctr = this.grid.getView().getFooterPanel(true);
36775 this.footer.dataSource = this.grid.dataSource;
36776 this.footer = Roo.factory(this.footer, Roo);
36777 this.footer.render(ctr);
36787 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36788 getId : function(){
36789 return this.grid.id;
36793 * Returns the grid for this panel
36794 * @return {Roo.bootstrap.Table}
36796 getGrid : function(){
36800 setSize : function(width, height){
36801 if(!this.ignoreResize(width, height)){
36802 var grid = this.grid;
36803 var size = this.adjustForComponents(width, height);
36804 var gridel = grid.getGridEl();
36805 gridel.setSize(size.width, size.height);
36807 var thd = grid.getGridEl().select('thead',true).first();
36808 var tbd = grid.getGridEl().select('tbody', true).first();
36810 tbd.setSize(width, height - thd.getHeight());
36819 beforeSlide : function(){
36820 this.grid.getView().scroller.clip();
36823 afterSlide : function(){
36824 this.grid.getView().scroller.unclip();
36827 destroy : function(){
36828 this.grid.destroy();
36830 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36835 * @class Roo.bootstrap.panel.Nest
36836 * @extends Roo.bootstrap.panel.Content
36838 * Create a new Panel, that can contain a layout.Border.
36841 * @param {Roo.BorderLayout} layout The layout for this panel
36842 * @param {String/Object} config A string to set only the title or a config object
36844 Roo.bootstrap.panel.Nest = function(config)
36846 // construct with only one argument..
36847 /* FIXME - implement nicer consturctors
36848 if (layout.layout) {
36850 layout = config.layout;
36851 delete config.layout;
36853 if (layout.xtype && !layout.getEl) {
36854 // then layout needs constructing..
36855 layout = Roo.factory(layout, Roo);
36859 config.el = config.layout.getEl();
36861 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36863 config.layout.monitorWindowResize = false; // turn off autosizing
36864 this.layout = config.layout;
36865 this.layout.getEl().addClass("roo-layout-nested-layout");
36872 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36874 setSize : function(width, height){
36875 if(!this.ignoreResize(width, height)){
36876 var size = this.adjustForComponents(width, height);
36877 var el = this.layout.getEl();
36878 if (size.height < 1) {
36879 el.setWidth(size.width);
36881 el.setSize(size.width, size.height);
36883 var touch = el.dom.offsetWidth;
36884 this.layout.layout();
36885 // ie requires a double layout on the first pass
36886 if(Roo.isIE && !this.initialized){
36887 this.initialized = true;
36888 this.layout.layout();
36893 // activate all subpanels if not currently active..
36895 setActiveState : function(active){
36896 this.active = active;
36897 this.setActiveClass(active);
36900 this.fireEvent("deactivate", this);
36904 this.fireEvent("activate", this);
36905 // not sure if this should happen before or after..
36906 if (!this.layout) {
36907 return; // should not happen..
36910 for (var r in this.layout.regions) {
36911 reg = this.layout.getRegion(r);
36912 if (reg.getActivePanel()) {
36913 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36914 reg.setActivePanel(reg.getActivePanel());
36917 if (!reg.panels.length) {
36920 reg.showPanel(reg.getPanel(0));
36929 * Returns the nested BorderLayout for this panel
36930 * @return {Roo.BorderLayout}
36932 getLayout : function(){
36933 return this.layout;
36937 * Adds a xtype elements to the layout of the nested panel
36941 xtype : 'ContentPanel',
36948 xtype : 'NestedLayoutPanel',
36954 items : [ ... list of content panels or nested layout panels.. ]
36958 * @param {Object} cfg Xtype definition of item to add.
36960 addxtype : function(cfg) {
36961 return this.layout.addxtype(cfg);
36966 * Ext JS Library 1.1.1
36967 * Copyright(c) 2006-2007, Ext JS, LLC.
36969 * Originally Released Under LGPL - original licence link has changed is not relivant.
36972 * <script type="text/javascript">
36975 * @class Roo.TabPanel
36976 * @extends Roo.util.Observable
36977 * A lightweight tab container.
36981 // basic tabs 1, built from existing content
36982 var tabs = new Roo.TabPanel("tabs1");
36983 tabs.addTab("script", "View Script");
36984 tabs.addTab("markup", "View Markup");
36985 tabs.activate("script");
36987 // more advanced tabs, built from javascript
36988 var jtabs = new Roo.TabPanel("jtabs");
36989 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36991 // set up the UpdateManager
36992 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36993 var updater = tab2.getUpdateManager();
36994 updater.setDefaultUrl("ajax1.htm");
36995 tab2.on('activate', updater.refresh, updater, true);
36997 // Use setUrl for Ajax loading
36998 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36999 tab3.setUrl("ajax2.htm", null, true);
37002 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37005 jtabs.activate("jtabs-1");
37008 * Create a new TabPanel.
37009 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37010 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37012 Roo.bootstrap.panel.Tabs = function(config){
37014 * The container element for this TabPanel.
37015 * @type Roo.Element
37017 this.el = Roo.get(config.el);
37020 if(typeof config == "boolean"){
37021 this.tabPosition = config ? "bottom" : "top";
37023 Roo.apply(this, config);
37027 if(this.tabPosition == "bottom"){
37028 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37029 this.el.addClass("roo-tabs-bottom");
37031 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37032 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37033 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37035 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37037 if(this.tabPosition != "bottom"){
37038 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37039 * @type Roo.Element
37041 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37042 this.el.addClass("roo-tabs-top");
37046 this.bodyEl.setStyle("position", "relative");
37048 this.active = null;
37049 this.activateDelegate = this.activate.createDelegate(this);
37054 * Fires when the active tab changes
37055 * @param {Roo.TabPanel} this
37056 * @param {Roo.TabPanelItem} activePanel The new active tab
37060 * @event beforetabchange
37061 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37062 * @param {Roo.TabPanel} this
37063 * @param {Object} e Set cancel to true on this object to cancel the tab change
37064 * @param {Roo.TabPanelItem} tab The tab being changed to
37066 "beforetabchange" : true
37069 Roo.EventManager.onWindowResize(this.onResize, this);
37070 this.cpad = this.el.getPadding("lr");
37071 this.hiddenCount = 0;
37074 // toolbar on the tabbar support...
37075 if (this.toolbar) {
37076 alert("no toolbar support yet");
37077 this.toolbar = false;
37079 var tcfg = this.toolbar;
37080 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37081 this.toolbar = new Roo.Toolbar(tcfg);
37082 if (Roo.isSafari) {
37083 var tbl = tcfg.container.child('table', true);
37084 tbl.setAttribute('width', '100%');
37092 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37095 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37097 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37099 tabPosition : "top",
37101 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37103 currentTabWidth : 0,
37105 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37109 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37113 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37115 preferredTabWidth : 175,
37117 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37119 resizeTabs : false,
37121 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37123 monitorResize : true,
37125 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37130 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37131 * @param {String} id The id of the div to use <b>or create</b>
37132 * @param {String} text The text for the tab
37133 * @param {String} content (optional) Content to put in the TabPanelItem body
37134 * @param {Boolean} closable (optional) True to create a close icon on the tab
37135 * @return {Roo.TabPanelItem} The created TabPanelItem
37137 addTab : function(id, text, content, closable, tpl)
37139 var item = new Roo.bootstrap.panel.TabItem({
37143 closable : closable,
37146 this.addTabItem(item);
37148 item.setContent(content);
37154 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37155 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37156 * @return {Roo.TabPanelItem}
37158 getTab : function(id){
37159 return this.items[id];
37163 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37164 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37166 hideTab : function(id){
37167 var t = this.items[id];
37170 this.hiddenCount++;
37171 this.autoSizeTabs();
37176 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37177 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37179 unhideTab : function(id){
37180 var t = this.items[id];
37182 t.setHidden(false);
37183 this.hiddenCount--;
37184 this.autoSizeTabs();
37189 * Adds an existing {@link Roo.TabPanelItem}.
37190 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37192 addTabItem : function(item){
37193 this.items[item.id] = item;
37194 this.items.push(item);
37195 // if(this.resizeTabs){
37196 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37197 // this.autoSizeTabs();
37199 // item.autoSize();
37204 * Removes a {@link Roo.TabPanelItem}.
37205 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37207 removeTab : function(id){
37208 var items = this.items;
37209 var tab = items[id];
37210 if(!tab) { return; }
37211 var index = items.indexOf(tab);
37212 if(this.active == tab && items.length > 1){
37213 var newTab = this.getNextAvailable(index);
37218 this.stripEl.dom.removeChild(tab.pnode.dom);
37219 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37220 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37222 items.splice(index, 1);
37223 delete this.items[tab.id];
37224 tab.fireEvent("close", tab);
37225 tab.purgeListeners();
37226 this.autoSizeTabs();
37229 getNextAvailable : function(start){
37230 var items = this.items;
37232 // look for a next tab that will slide over to
37233 // replace the one being removed
37234 while(index < items.length){
37235 var item = items[++index];
37236 if(item && !item.isHidden()){
37240 // if one isn't found select the previous tab (on the left)
37243 var item = items[--index];
37244 if(item && !item.isHidden()){
37252 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37253 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37255 disableTab : function(id){
37256 var tab = this.items[id];
37257 if(tab && this.active != tab){
37263 * Enables a {@link Roo.TabPanelItem} that is disabled.
37264 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37266 enableTab : function(id){
37267 var tab = this.items[id];
37272 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37273 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37274 * @return {Roo.TabPanelItem} The TabPanelItem.
37276 activate : function(id){
37277 var tab = this.items[id];
37281 if(tab == this.active || tab.disabled){
37285 this.fireEvent("beforetabchange", this, e, tab);
37286 if(e.cancel !== true && !tab.disabled){
37288 this.active.hide();
37290 this.active = this.items[id];
37291 this.active.show();
37292 this.fireEvent("tabchange", this, this.active);
37298 * Gets the active {@link Roo.TabPanelItem}.
37299 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37301 getActiveTab : function(){
37302 return this.active;
37306 * Updates the tab body element to fit the height of the container element
37307 * for overflow scrolling
37308 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37310 syncHeight : function(targetHeight){
37311 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37312 var bm = this.bodyEl.getMargins();
37313 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37314 this.bodyEl.setHeight(newHeight);
37318 onResize : function(){
37319 if(this.monitorResize){
37320 this.autoSizeTabs();
37325 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37327 beginUpdate : function(){
37328 this.updating = true;
37332 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37334 endUpdate : function(){
37335 this.updating = false;
37336 this.autoSizeTabs();
37340 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37342 autoSizeTabs : function(){
37343 var count = this.items.length;
37344 var vcount = count - this.hiddenCount;
37345 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37348 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37349 var availWidth = Math.floor(w / vcount);
37350 var b = this.stripBody;
37351 if(b.getWidth() > w){
37352 var tabs = this.items;
37353 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37354 if(availWidth < this.minTabWidth){
37355 /*if(!this.sleft){ // incomplete scrolling code
37356 this.createScrollButtons();
37359 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37362 if(this.currentTabWidth < this.preferredTabWidth){
37363 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37369 * Returns the number of tabs in this TabPanel.
37372 getCount : function(){
37373 return this.items.length;
37377 * Resizes all the tabs to the passed width
37378 * @param {Number} The new width
37380 setTabWidth : function(width){
37381 this.currentTabWidth = width;
37382 for(var i = 0, len = this.items.length; i < len; i++) {
37383 if(!this.items[i].isHidden()) {
37384 this.items[i].setWidth(width);
37390 * Destroys this TabPanel
37391 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37393 destroy : function(removeEl){
37394 Roo.EventManager.removeResizeListener(this.onResize, this);
37395 for(var i = 0, len = this.items.length; i < len; i++){
37396 this.items[i].purgeListeners();
37398 if(removeEl === true){
37399 this.el.update("");
37404 createStrip : function(container)
37406 var strip = document.createElement("nav");
37407 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37408 container.appendChild(strip);
37412 createStripList : function(strip)
37414 // div wrapper for retard IE
37415 // returns the "tr" element.
37416 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37417 //'<div class="x-tabs-strip-wrap">'+
37418 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37419 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37420 return strip.firstChild; //.firstChild.firstChild.firstChild;
37422 createBody : function(container)
37424 var body = document.createElement("div");
37425 Roo.id(body, "tab-body");
37426 //Roo.fly(body).addClass("x-tabs-body");
37427 Roo.fly(body).addClass("tab-content");
37428 container.appendChild(body);
37431 createItemBody :function(bodyEl, id){
37432 var body = Roo.getDom(id);
37434 body = document.createElement("div");
37437 //Roo.fly(body).addClass("x-tabs-item-body");
37438 Roo.fly(body).addClass("tab-pane");
37439 bodyEl.insertBefore(body, bodyEl.firstChild);
37443 createStripElements : function(stripEl, text, closable, tpl)
37445 var td = document.createElement("li"); // was td..
37448 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37451 stripEl.appendChild(td);
37453 td.className = "x-tabs-closable";
37454 if(!this.closeTpl){
37455 this.closeTpl = new Roo.Template(
37456 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37457 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37458 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37461 var el = this.closeTpl.overwrite(td, {"text": text});
37462 var close = el.getElementsByTagName("div")[0];
37463 var inner = el.getElementsByTagName("em")[0];
37464 return {"el": el, "close": close, "inner": inner};
37467 // not sure what this is..
37468 // if(!this.tabTpl){
37469 //this.tabTpl = new Roo.Template(
37470 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37471 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37473 // this.tabTpl = new Roo.Template(
37474 // '<a href="#">' +
37475 // '<span unselectable="on"' +
37476 // (this.disableTooltips ? '' : ' title="{text}"') +
37477 // ' >{text}</span></a>'
37483 var template = tpl || this.tabTpl || false;
37487 template = new Roo.Template(
37489 '<span unselectable="on"' +
37490 (this.disableTooltips ? '' : ' title="{text}"') +
37491 ' >{text}</span></a>'
37495 switch (typeof(template)) {
37499 template = new Roo.Template(template);
37505 var el = template.overwrite(td, {"text": text});
37507 var inner = el.getElementsByTagName("span")[0];
37509 return {"el": el, "inner": inner};
37517 * @class Roo.TabPanelItem
37518 * @extends Roo.util.Observable
37519 * Represents an individual item (tab plus body) in a TabPanel.
37520 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37521 * @param {String} id The id of this TabPanelItem
37522 * @param {String} text The text for the tab of this TabPanelItem
37523 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37525 Roo.bootstrap.panel.TabItem = function(config){
37527 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37528 * @type Roo.TabPanel
37530 this.tabPanel = config.panel;
37532 * The id for this TabPanelItem
37535 this.id = config.id;
37537 this.disabled = false;
37539 this.text = config.text;
37541 this.loaded = false;
37542 this.closable = config.closable;
37545 * The body element for this TabPanelItem.
37546 * @type Roo.Element
37548 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37549 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37550 this.bodyEl.setStyle("display", "block");
37551 this.bodyEl.setStyle("zoom", "1");
37552 //this.hideAction();
37554 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37556 this.el = Roo.get(els.el);
37557 this.inner = Roo.get(els.inner, true);
37558 this.textEl = Roo.get(this.el.dom.firstChild, true);
37559 this.pnode = Roo.get(els.el.parentNode, true);
37560 this.el.on("mousedown", this.onTabMouseDown, this);
37561 this.el.on("click", this.onTabClick, this);
37563 if(config.closable){
37564 var c = Roo.get(els.close, true);
37565 c.dom.title = this.closeText;
37566 c.addClassOnOver("close-over");
37567 c.on("click", this.closeClick, this);
37573 * Fires when this tab becomes the active tab.
37574 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37575 * @param {Roo.TabPanelItem} this
37579 * @event beforeclose
37580 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37581 * @param {Roo.TabPanelItem} this
37582 * @param {Object} e Set cancel to true on this object to cancel the close.
37584 "beforeclose": true,
37587 * Fires when this tab is closed.
37588 * @param {Roo.TabPanelItem} this
37592 * @event deactivate
37593 * Fires when this tab is no longer the active tab.
37594 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37595 * @param {Roo.TabPanelItem} this
37597 "deactivate" : true
37599 this.hidden = false;
37601 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37604 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37606 purgeListeners : function(){
37607 Roo.util.Observable.prototype.purgeListeners.call(this);
37608 this.el.removeAllListeners();
37611 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37614 this.pnode.addClass("active");
37617 this.tabPanel.stripWrap.repaint();
37619 this.fireEvent("activate", this.tabPanel, this);
37623 * Returns true if this tab is the active tab.
37624 * @return {Boolean}
37626 isActive : function(){
37627 return this.tabPanel.getActiveTab() == this;
37631 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37634 this.pnode.removeClass("active");
37636 this.fireEvent("deactivate", this.tabPanel, this);
37639 hideAction : function(){
37640 this.bodyEl.hide();
37641 this.bodyEl.setStyle("position", "absolute");
37642 this.bodyEl.setLeft("-20000px");
37643 this.bodyEl.setTop("-20000px");
37646 showAction : function(){
37647 this.bodyEl.setStyle("position", "relative");
37648 this.bodyEl.setTop("");
37649 this.bodyEl.setLeft("");
37650 this.bodyEl.show();
37654 * Set the tooltip for the tab.
37655 * @param {String} tooltip The tab's tooltip
37657 setTooltip : function(text){
37658 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37659 this.textEl.dom.qtip = text;
37660 this.textEl.dom.removeAttribute('title');
37662 this.textEl.dom.title = text;
37666 onTabClick : function(e){
37667 e.preventDefault();
37668 this.tabPanel.activate(this.id);
37671 onTabMouseDown : function(e){
37672 e.preventDefault();
37673 this.tabPanel.activate(this.id);
37676 getWidth : function(){
37677 return this.inner.getWidth();
37680 setWidth : function(width){
37681 var iwidth = width - this.pnode.getPadding("lr");
37682 this.inner.setWidth(iwidth);
37683 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37684 this.pnode.setWidth(width);
37688 * Show or hide the tab
37689 * @param {Boolean} hidden True to hide or false to show.
37691 setHidden : function(hidden){
37692 this.hidden = hidden;
37693 this.pnode.setStyle("display", hidden ? "none" : "");
37697 * Returns true if this tab is "hidden"
37698 * @return {Boolean}
37700 isHidden : function(){
37701 return this.hidden;
37705 * Returns the text for this tab
37708 getText : function(){
37712 autoSize : function(){
37713 //this.el.beginMeasure();
37714 this.textEl.setWidth(1);
37716 * #2804 [new] Tabs in Roojs
37717 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37719 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37720 //this.el.endMeasure();
37724 * Sets the text for the tab (Note: this also sets the tooltip text)
37725 * @param {String} text The tab's text and tooltip
37727 setText : function(text){
37729 this.textEl.update(text);
37730 this.setTooltip(text);
37731 //if(!this.tabPanel.resizeTabs){
37732 // this.autoSize();
37736 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37738 activate : function(){
37739 this.tabPanel.activate(this.id);
37743 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37745 disable : function(){
37746 if(this.tabPanel.active != this){
37747 this.disabled = true;
37748 this.pnode.addClass("disabled");
37753 * Enables this TabPanelItem if it was previously disabled.
37755 enable : function(){
37756 this.disabled = false;
37757 this.pnode.removeClass("disabled");
37761 * Sets the content for this TabPanelItem.
37762 * @param {String} content The content
37763 * @param {Boolean} loadScripts true to look for and load scripts
37765 setContent : function(content, loadScripts){
37766 this.bodyEl.update(content, loadScripts);
37770 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37771 * @return {Roo.UpdateManager} The UpdateManager
37773 getUpdateManager : function(){
37774 return this.bodyEl.getUpdateManager();
37778 * Set a URL to be used to load the content for this TabPanelItem.
37779 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37780 * @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)
37781 * @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)
37782 * @return {Roo.UpdateManager} The UpdateManager
37784 setUrl : function(url, params, loadOnce){
37785 if(this.refreshDelegate){
37786 this.un('activate', this.refreshDelegate);
37788 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37789 this.on("activate", this.refreshDelegate);
37790 return this.bodyEl.getUpdateManager();
37794 _handleRefresh : function(url, params, loadOnce){
37795 if(!loadOnce || !this.loaded){
37796 var updater = this.bodyEl.getUpdateManager();
37797 updater.update(url, params, this._setLoaded.createDelegate(this));
37802 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37803 * Will fail silently if the setUrl method has not been called.
37804 * This does not activate the panel, just updates its content.
37806 refresh : function(){
37807 if(this.refreshDelegate){
37808 this.loaded = false;
37809 this.refreshDelegate();
37814 _setLoaded : function(){
37815 this.loaded = true;
37819 closeClick : function(e){
37822 this.fireEvent("beforeclose", this, o);
37823 if(o.cancel !== true){
37824 this.tabPanel.removeTab(this.id);
37828 * The text displayed in the tooltip for the close icon.
37831 closeText : "Close this tab"
37841 * @class Roo.bootstrap.PhoneInput
37842 * @extends Roo.bootstrap.TriggerField
37843 * Bootstrap PhoneInput class
37846 * Create a new PhoneInput
37847 * @param {Object} config The config object
37850 Roo.bootstrap.PhoneInput = function(config){
37852 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
37857 * Fires when the dropdown list is expanded
37858 * @param {Roo.bootstrap.ComboBox} combo This combo box
37863 * Fires when the dropdown list is collapsed
37864 * @param {Roo.bootstrap.ComboBox} combo This combo box
37868 * @event beforeselect
37869 * Fires before a list item is selected. Return false to cancel the selection.
37870 * @param {Roo.bootstrap.ComboBox} combo This combo box
37871 * @param {Roo.data.Record} record The data record returned from the underlying store
37872 * @param {Number} index The index of the selected item in the dropdown list
37874 'beforeselect' : true,
37877 * Fires when a list item is selected
37878 * @param {Roo.bootstrap.ComboBox} combo This combo box
37879 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37880 * @param {Number} index The index of the selected item in the dropdown list
37884 * @event beforequery
37885 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37886 * The event object passed has these properties:
37887 * @param {Roo.bootstrap.ComboBox} combo This combo box
37888 * @param {String} query The query
37889 * @param {Boolean} forceAll true to force "all" query
37890 * @param {Boolean} cancel true to cancel the query
37891 * @param {Object} e The query event object
37893 'beforequery': true,
37896 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37897 * @param {Roo.bootstrap.ComboBox} combo This combo box
37902 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37903 * @param {Roo.bootstrap.ComboBox} combo This combo box
37904 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37909 * Fires when the remove value from the combobox array
37910 * @param {Roo.bootstrap.ComboBox} combo This combo box
37914 * @event afterremove
37915 * Fires when the remove value from the combobox array
37916 * @param {Roo.bootstrap.ComboBox} combo This combo box
37918 'afterremove' : true,
37920 * @event specialfilter
37921 * Fires when specialfilter
37922 * @param {Roo.bootstrap.ComboBox} combo This combo box
37924 'touchviewdisplay' : true
37927 this.country = []; //fetch country JSON
37930 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
37932 listWidth: undefined,
37936 selectedClass: 'active',
37942 triggerAction: 'query',
37944 validClass : "has-success",
37946 invalidClass: "has-warning",
37949 defaultCountry: 'hk',
37951 preferedCountries: undefined, //array
37953 filterCountries: undefined, //array
37955 displayMode: undefined, //string
37957 getAutoCreate : function(){
37959 this.list = Roo.bootstrap.PhoneInput.List;
37961 if(this.filterCountries) {
37962 for(var i = 0; i < this.filterCountries.length; i++) {
37963 delete this.list[this.filterCountries[i]];
37967 if (this.preferedCountries) {
37971 var align = this.labelAlign || this.parentLabelAlign();
37973 var id = Roo.id(); //all el??
37982 type : this.inputType,
37983 cls : 'form-control',
37984 style: 'padding-left: 60px;',
37985 placeholder : this.placeholder || ''
37989 input.name = this.name;
37992 input.cls += ' input-' + this.size;
37995 if (this.disabled) {
37996 input.disabled=true;
37999 var inputblock = input;
38001 if(this.hasFeedback && !this.allowBlank){
38004 cls: 'glyphicon form-control-feedback'
38012 inputblock.cn.push(input);
38014 if(this.hasFeedback && !this.allowBlank){
38015 inputblock.cls += 'has-feedback';
38016 inputblock.cn.push(feedback);
38025 cls: 'form-hidden-field'
38034 style: 'margin-right:5px',
38035 cls: 'roo-selected-region',
38036 cn: [] //flag position ... (iti-flag-us)
38044 if (this.caret != false) {
38047 cls: 'fa fa-' + this.caret
38052 cls: 'roo-select2-container input-group',
38058 cls : 'input-group-addon btn dropdown-toggle',
38059 style : 'position: absolute; z-index: 4;background: none;border: none; margin-top: 4px; margin-left: 3px; margin-right: 3px;',
38065 cls: 'combobox-clear',
38076 combobox.cn.push(box);
38078 if (align ==='left' && this.fieldLabel.length) {
38080 cfg.cls += ' roo-form-group-label-left';
38085 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
38086 tooltip : 'This field is required'
38091 cls : 'control-label',
38092 html : this.fieldLabel
38103 var labelCfg = cfg.cn[1];
38104 var contentCfg = cfg.cn[2];
38106 if(this.indicatorpos == 'right'){
38111 cls : 'control-label',
38115 html : this.fieldLabel
38119 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
38120 tooltip : 'This field is required'
38133 labelCfg = cfg.cn[0];
38134 contentCfg = cfg.cn[1];
38137 if(this.labelWidth > 12){
38138 labelCfg.style = "width: " + this.labelWidth + 'px';
38141 if(this.labelWidth < 13 && this.labelmd == 0){
38142 this.labelmd = this.labelWidth;
38145 if(this.labellg > 0){
38146 labelCfg.cls += ' col-lg-' + this.labellg;
38147 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
38150 if(this.labelmd > 0){
38151 labelCfg.cls += ' col-md-' + this.labelmd;
38152 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
38155 if(this.labelsm > 0){
38156 labelCfg.cls += ' col-sm-' + this.labelsm;
38157 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
38160 if(this.labelxs > 0){
38161 labelCfg.cls += ' col-xs-' + this.labelxs;
38162 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
38165 } else if ( this.fieldLabel.length) {
38166 // Roo.log(" label");
38170 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
38171 tooltip : 'This field is required'
38175 //cls : 'input-group-addon',
38176 html : this.fieldLabel
38184 if(this.indicatorpos == 'right'){
38192 html : this.fieldLabel
38196 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
38197 tooltip : 'This field is required'
38209 ['xs','sm','md','lg'].map(function(size){
38210 if (settings[size]) {
38211 cfg.cls += ' col-' + size + '-' + settings[size];
38218 _initEventsCalled : false,
38220 initEvents: function()
38222 if (this._initEventsCalled) {
38226 this._initEventsCalled = true;
38228 this.store = new Roo.data.SimpleStore({
38230 fields : ['name','iso','dial_code','order','area_code']
38233 this.store = Roo.factory(this.store, Roo.data);
38234 this.store.parent = this;
38236 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
38241 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
38242 _this.list.setWidth(lw);
38245 this.list.on('mouseover', this.onViewOver, this);
38246 this.list.on('mousemove', this.onViewMove, this);
38247 this.list.on('scroll', this.onViewScroll, this);
38250 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
38253 this.view = new Roo.View(this.list, this.tpl, {
38254 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38257 this.view.on('click', this.onViewClick, this);
38259 this.store.on('beforeload', this.onBeforeLoad, this);
38260 this.store.on('load', this.onLoad, this);
38261 this.store.on('loadexception', this.onLoadException, this);
38263 this.keyNav = new Roo.KeyNav(this.inputEl(), {
38264 "up" : function(e){
38265 this.inKeyMode = true;
38269 "down" : function(e){
38270 if(!this.isExpanded()){
38271 this.onTriggerClick();
38273 this.inKeyMode = true;
38278 "enter" : function(e){
38279 // this.onViewClick();
38283 if(this.fireEvent("specialkey", this, e)){
38284 this.onViewClick(false);
38290 "esc" : function(e){
38294 "tab" : function(e){
38297 if(this.fireEvent("specialkey", this, e)){
38298 this.onViewClick(false);
38306 doRelay : function(foo, bar, hname){
38307 if(hname == 'down' || this.scope.isExpanded()){
38308 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38318 onViewOver : function(e, t){
38319 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
38322 var item = this.view.findItemFromChild(t);
38325 var index = this.view.indexOf(item);
38326 this.select(index, false);
38330 onViewMove : function(e, t){
38331 this.inKeyMode = false;
38334 onViewScroll : function(e, t){
38336 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){
38340 this.hasQuery = true;
38342 this.loading = this.list.select('.loading', true).first();
38344 if(this.loading === null){
38345 this.list.createChild({
38347 cls: 'loading roo-select2-more-results roo-select2-active',
38348 html: 'Loading more results...'
38351 this.loading = this.list.select('.loading', true).first();
38353 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
38355 this.loading.hide();
38358 this.loading.show();
38363 this.loadNext = true;
38365 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
38370 onTriggerClick : function(e)
38372 Roo.log('trigger click');
38374 if(this.disabled || !this.triggerList){
38379 this.loadNext = false;
38381 if(this.isExpanded()){
38383 if (!this.blockFocus) {
38384 this.inputEl().focus();
38388 this.hasFocus = true;
38389 if(this.triggerAction == 'all') {
38390 this.doQuery(this.allQuery, true);
38392 this.doQuery(this.getRawValue());
38394 if (!this.blockFocus) {
38395 this.inputEl().focus();
38402 Roo.apply(Roo.bootstrap.PhoneInput, {
38405 * iso2 and abbr for all countries
38409 ["Afghanistan (افغانستان)", "af", "93"],
38410 ["Albania (Shqipëri)", "al", "355"],
38411 ["Algeria (الجزائر)", "dz", "213"],
38412 ["American Samoa", "as", "1684"],
38413 ["Andorra", "ad", "376"],
38414 ["Angola", "ao", "244"],
38415 ["Anguilla", "ai", "1264"],
38416 ["Antigua and Barbuda", "ag", "1268"],
38417 ["Argentina", "ar", "54"],
38418 ["Armenia (Հայաստան)", "am", "374"],
38419 ["Aruba", "aw", "297"],
38420 ["Australia", "au", "61", 0],
38421 ["Austria (Österreich)", "at", "43"],
38422 ["Azerbaijan (Azərbaycan)", "az", "994"],
38423 ["Bahamas", "bs", "1242"],
38424 ["Bahrain (البحرين)", "bh", "973"],
38425 ["Bangladesh (বাংলাদেশ)", "bd", "880"],
38426 ["Barbados", "bb", "1246"],
38427 ["Belarus (Беларусь)", "by", "375"],
38428 ["Belgium (België)", "be", "32"],
38429 ["Belize", "bz", "501"],
38430 ["Benin (Bénin)", "bj", "229"],
38431 ["Bermuda", "bm", "1441"],
38432 ["Bhutan (འབྲུག)", "bt", "975"],
38433 ["Bolivia", "bo", "591"],
38434 ["Bosnia and Herzegovina (Босна и Херцеговина)", "ba", "387"],
38435 ["Botswana", "bw", "267"],
38436 ["Brazil (Brasil)", "br", "55"],
38437 ["British Indian Ocean Territory", "io", "246"],
38438 ["British Virgin Islands", "vg", "1284"],
38439 ["Brunei", "bn", "673"],
38440 ["Bulgaria (България)", "bg", "359"],
38441 ["Burkina Faso", "bf", "226"],
38442 ["Burundi (Uburundi)", "bi", "257"],
38443 ["Cambodia (កម្ពុជា)", "kh", "855"],
38444 ["Cameroon (Cameroun)", "cm", "237"],
38445 ["Canada", "ca", "1", 1, ["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"]],
38446 ["Cape Verde (Kabu Verdi)", "cv", "238"],
38447 ["Caribbean Netherlands", "bq", "599", 1],
38448 ["Cayman Islands", "ky", "1345"],
38449 ["Central African Republic (République centrafricaine)", "cf", "236"],
38450 ["Chad (Tchad)", "td", "235"],
38451 ["Chile", "cl", "56"],
38452 ["China (中国)", "cn", "86"],
38453 ["Christmas Island", "cx", "61", 2],
38454 ["Cocos (Keeling) Islands", "cc", "61", 1],
38455 ["Colombia", "co", "57"],
38456 ["Comoros (جزر القمر)", "km", "269"],
38457 ["Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)", "cd", "243"],
38458 ["Congo (Republic) (Congo-Brazzaville)", "cg", "242"],
38459 ["Cook Islands", "ck", "682"],
38460 ["Costa Rica", "cr", "506"],
38461 ["Côte d’Ivoire", "ci", "225"],
38462 ["Croatia (Hrvatska)", "hr", "385"],
38463 ["Cuba", "cu", "53"],
38464 ["Curaçao", "cw", "599", 0],
38465 ["Cyprus (Κύπρος)", "cy", "357"],
38466 ["Czech Republic (Česká republika)", "cz", "420"],
38467 ["Denmark (Danmark)", "dk", "45"],
38468 ["Djibouti", "dj", "253"],
38469 ["Dominica", "dm", "1767"],
38470 ["Dominican Republic (República Dominicana)", "do", "1", 2, ["809", "829", "849"]],
38471 ["Ecuador", "ec", "593"],
38472 ["Egypt (مصر)", "eg", "20"],
38473 ["El Salvador", "sv", "503"],
38474 ["Equatorial Guinea (Guinea Ecuatorial)", "gq", "240"],
38475 ["Eritrea", "er", "291"],
38476 ["Estonia (Eesti)", "ee", "372"],
38477 ["Ethiopia", "et", "251"],
38478 ["Falkland Islands (Islas Malvinas)", "fk", "500"],
38479 ["Faroe Islands (Føroyar)", "fo", "298"],
38480 ["Fiji", "fj", "679"],
38481 ["Finland (Suomi)", "fi", "358", 0],
38482 ["France", "fr", "33"],
38483 ["French Guiana (Guyane française)", "gf", "594"],
38484 ["French Polynesia (Polynésie française)", "pf", "689"],
38485 ["Gabon", "ga", "241"],
38486 ["Gambia", "gm", "220"],
38487 ["Georgia (საქართველო)", "ge", "995"],
38488 ["Germany (Deutschland)", "de", "49"],
38489 ["Ghana (Gaana)", "gh", "233"],
38490 ["Gibraltar", "gi", "350"],
38491 ["Greece (Ελλάδα)", "gr", "30"],
38492 ["Greenland (Kalaallit Nunaat)", "gl", "299"],
38493 ["Grenada", "gd", "1473"],
38494 ["Guadeloupe", "gp", "590", 0],
38495 ["Guam", "gu", "1671"],
38496 ["Guatemala", "gt", "502"],
38497 ["Guernsey", "gg", "44", 1],
38498 ["Guinea (Guinée)", "gn", "224"],
38499 ["Guinea-Bissau (Guiné Bissau)", "gw", "245"],
38500 ["Guyana", "gy", "592"],
38501 ["Haiti", "ht", "509"],
38502 ["Honduras", "hn", "504"],
38503 ["Hong Kong (香港)", "hk", "852"],
38504 ["Hungary (Magyarország)", "hu", "36"],
38505 ["Iceland (Ísland)", "is", "354"],
38506 ["India (भारत)", "in", "91"],
38507 ["Indonesia", "id", "62"],
38508 ["Iran (ایران)", "ir", "98"],
38509 ["Iraq (العراق)", "iq", "964"],
38510 ["Ireland", "ie", "353"],
38511 ["Isle of Man", "im", "44", 2],
38512 ["Israel (ישראל)", "il", "972"],
38513 ["Italy (Italia)", "it", "39", 0],
38514 ["Jamaica", "jm", "1876"],
38515 ["Japan (日本)", "jp", "81"],
38516 ["Jersey", "je", "44", 3],
38517 ["Jordan (الأردن)", "jo", "962"],
38518 ["Kazakhstan (Казахстан)", "kz", "7", 1],
38519 ["Kenya", "ke", "254"],
38520 ["Kiribati", "ki", "686"],
38521 ["Kosovo", "xk", "383"],
38522 ["Kuwait (الكويت)", "kw", "965"],
38523 ["Kyrgyzstan (Кыргызстан)", "kg", "996"],
38524 ["Laos (ລາວ)", "la", "856"],
38525 ["Latvia (Latvija)", "lv", "371"],
38526 ["Lebanon (لبنان)", "lb", "961"],
38527 ["Lesotho", "ls", "266"],
38528 ["Liberia", "lr", "231"],
38529 ["Libya (ليبيا)", "ly", "218"],
38530 ["Liechtenstein", "li", "423"],
38531 ["Lithuania (Lietuva)", "lt", "370"],
38532 ["Luxembourg", "lu", "352"],
38533 ["Macau (澳門)", "mo", "853"],
38534 ["Macedonia (FYROM) (Македонија)", "mk", "389"],
38535 ["Madagascar (Madagasikara)", "mg", "261"],
38536 ["Malawi", "mw", "265"],
38537 ["Malaysia", "my", "60"],
38538 ["Maldives", "mv", "960"],
38539 ["Mali", "ml", "223"],
38540 ["Malta", "mt", "356"],
38541 ["Marshall Islands", "mh", "692"],
38542 ["Martinique", "mq", "596"],
38543 ["Mauritania (موريتانيا)", "mr", "222"],
38544 ["Mauritius (Moris)", "mu", "230"],
38545 ["Mayotte", "yt", "262", 1],
38546 ["Mexico (México)", "mx", "52"],
38547 ["Micronesia", "fm", "691"],
38548 ["Moldova (Republica Moldova)", "md", "373"],
38549 ["Monaco", "mc", "377"],
38550 ["Mongolia (Монгол)", "mn", "976"],
38551 ["Montenegro (Crna Gora)", "me", "382"],
38552 ["Montserrat", "ms", "1664"],
38553 ["Morocco (المغرب)", "ma", "212", 0],
38554 ["Mozambique (Moçambique)", "mz", "258"],
38555 ["Myanmar (Burma) (မြန်မာ)", "mm", "95"],
38556 ["Namibia (Namibië)", "na", "264"],
38557 ["Nauru", "nr", "674"],
38558 ["Nepal (नेपाल)", "np", "977"],
38559 ["Netherlands (Nederland)", "nl", "31"],
38560 ["New Caledonia (Nouvelle-Calédonie)", "nc", "687"],
38561 ["New Zealand", "nz", "64"],
38562 ["Nicaragua", "ni", "505"],
38563 ["Niger (Nijar)", "ne", "227"],
38564 ["Nigeria", "ng", "234"],
38565 ["Niue", "nu", "683"],
38566 ["Norfolk Island", "nf", "672"],
38567 ["North Korea (조선 민주주의 인민 공화국)", "kp", "850"],
38568 ["Northern Mariana Islands", "mp", "1670"],
38569 ["Norway (Norge)", "no", "47", 0],
38570 ["Oman (عُمان)", "om", "968"],
38571 ["Pakistan (پاکستان)", "pk", "92"],
38572 ["Palau", "pw", "680"],
38573 ["Palestine (فلسطين)", "ps", "970"],
38574 ["Panama (Panamá)", "pa", "507"],
38575 ["Papua New Guinea", "pg", "675"],
38576 ["Paraguay", "py", "595"],
38577 ["Peru (Perú)", "pe", "51"],
38578 ["Philippines", "ph", "63"],
38579 ["Poland (Polska)", "pl", "48"],
38580 ["Portugal", "pt", "351"],
38581 ["Puerto Rico", "pr", "1", 3, ["787", "939"]],
38582 ["Qatar (قطر)", "qa", "974"],
38583 ["Réunion (La Réunion)", "re", "262", 0],
38584 ["Romania (România)", "ro", "40"],
38585 ["Russia (Россия)", "ru", "7", 0],
38586 ["Rwanda", "rw", "250"],
38587 ["Saint Barthélemy", "bl", "590", 1],
38588 ["Saint Helena", "sh", "290"],
38589 ["Saint Kitts and Nevis", "kn", "1869"],
38590 ["Saint Lucia", "lc", "1758"],
38591 ["Saint Martin (Saint-Martin (partie française))", "mf", "590", 2],
38592 ["Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)", "pm", "508"],
38593 ["Saint Vincent and the Grenadines", "vc", "1784"],
38594 ["Samoa", "ws", "685"],
38595 ["San Marino", "sm", "378"],
38596 ["São Tomé and Príncipe (São Tomé e Príncipe)", "st", "239"],
38597 ["Saudi Arabia (المملكة العربية السعودية)", "sa", "966"],
38598 ["Senegal (Sénégal)", "sn", "221"],
38599 ["Serbia (Србија)", "rs", "381"],
38600 ["Seychelles", "sc", "248"],
38601 ["Sierra Leone", "sl", "232"],
38602 ["Singapore", "sg", "65"],
38603 ["Sint Maarten", "sx", "1721"],
38604 ["Slovakia (Slovensko)", "sk", "421"],
38605 ["Slovenia (Slovenija)", "si", "386"],
38606 ["Solomon Islands", "sb", "677"],
38607 ["Somalia (Soomaaliya)", "so", "252"],
38608 ["South Africa", "za", "27"],
38609 ["South Korea (대한민국)", "kr", "82"],
38610 ["South Sudan (جنوب السودان)", "ss", "211"],
38611 ["Spain (España)", "es", "34"],
38612 ["Sri Lanka (ශ්රී ලංකාව)", "lk", "94"],
38613 ["Sudan (السودان)", "sd", "249"],
38614 ["Suriname", "sr", "597"],
38615 ["Svalbard and Jan Mayen", "sj", "47", 1],
38616 ["Swaziland", "sz", "268"],
38617 ["Sweden (Sverige)", "se", "46"],
38618 ["Switzerland (Schweiz)", "ch", "41"],
38619 ["Syria (سوريا)", "sy", "963"],
38620 ["Taiwan (台灣)", "tw", "886"],
38621 ["Tajikistan", "tj", "992"],
38622 ["Tanzania", "tz", "255"],
38623 ["Thailand (ไทย)", "th", "66"],
38624 ["Timor-Leste", "tl", "670"],
38625 ["Togo", "tg", "228"],
38626 ["Tokelau", "tk", "690"],
38627 ["Tonga", "to", "676"],
38628 ["Trinidad and Tobago", "tt", "1868"],
38629 ["Tunisia (تونس)", "tn", "216"],
38630 ["Turkey (Türkiye)", "tr", "90"],
38631 ["Turkmenistan", "tm", "993"],
38632 ["Turks and Caicos Islands", "tc", "1649"],
38633 ["Tuvalu", "tv", "688"],
38634 ["U.S. Virgin Islands", "vi", "1340"],
38635 ["Uganda", "ug", "256"],
38636 ["Ukraine (Україна)", "ua", "380"],
38637 ["United Arab Emirates (الإمارات العربية المتحدة)", "ae", "971"],
38638 ["United Kingdom", "gb", "44", 0],
38639 ["United States", "us", "1", 0],
38640 ["Uruguay", "uy", "598"],
38641 ["Uzbekistan (Oʻzbekiston)", "uz", "998"],
38642 ["Vanuatu", "vu", "678"],
38643 ["Vatican City (Città del Vaticano)", "va", "39", 1],
38644 ["Venezuela", "ve", "58"],
38645 ["Vietnam (Việt Nam)", "vn", "84"],
38646 ["Wallis and Futuna (Wallis-et-Futuna)", "wf", "681"],
38647 ["Western Sahara (الصحراء الغربية)", "eh", "212", 1],
38648 ["Yemen (اليمن)", "ye", "967"],
38649 ["Zambia", "zm", "260"],
38650 ["Zimbabwe", "zw", "263"],
38651 ["Åland Islands", "ax", "358", 1]