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');
384 * @class Roo.bootstrap.Body
385 * @extends Roo.bootstrap.Component
386 * Bootstrap Body class
390 * @param {Object} config The config object
393 Roo.bootstrap.Body = function(config){
395 config = config || {};
397 Roo.bootstrap.Body.superclass.constructor.call(this, config);
398 this.el = Roo.get(config.el ? config.el : document.body );
399 if (this.cls && this.cls.length) {
400 Roo.get(document.body).addClass(this.cls);
404 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
406 is_body : true,// just to make sure it's constructed?
411 onRender : function(ct, position)
413 /* Roo.log("Roo.bootstrap.Body - onRender");
414 if (this.cls && this.cls.length) {
415 Roo.get(document.body).addClass(this.cls);
434 * @class Roo.bootstrap.ButtonGroup
435 * @extends Roo.bootstrap.Component
436 * Bootstrap ButtonGroup class
437 * @cfg {String} size lg | sm | xs (default empty normal)
438 * @cfg {String} align vertical | justified (default none)
439 * @cfg {String} direction up | down (default down)
440 * @cfg {Boolean} toolbar false | true
441 * @cfg {Boolean} btn true | false
446 * @param {Object} config The config object
449 Roo.bootstrap.ButtonGroup = function(config){
450 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
453 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
461 getAutoCreate : function(){
467 cfg.html = this.html || cfg.html;
478 if (['vertical','justified'].indexOf(this.align)!==-1) {
479 cfg.cls = 'btn-group-' + this.align;
481 if (this.align == 'justified') {
482 console.log(this.items);
486 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
487 cfg.cls += ' btn-group-' + this.size;
490 if (this.direction == 'up') {
491 cfg.cls += ' dropup' ;
507 * @class Roo.bootstrap.Button
508 * @extends Roo.bootstrap.Component
509 * Bootstrap Button class
510 * @cfg {String} html The button content
511 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
512 * @cfg {String} size ( lg | sm | xs)
513 * @cfg {String} tag ( a | input | submit)
514 * @cfg {String} href empty or href
515 * @cfg {Boolean} disabled default false;
516 * @cfg {Boolean} isClose default false;
517 * @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)
518 * @cfg {String} badge text for badge
519 * @cfg {String} theme default
520 * @cfg {Boolean} inverse
521 * @cfg {Boolean} toggle
522 * @cfg {String} ontext text for on toggle state
523 * @cfg {String} offtext text for off toggle state
524 * @cfg {Boolean} defaulton
525 * @cfg {Boolean} preventDefault default true
526 * @cfg {Boolean} removeClass remove the standard class..
527 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
530 * Create a new button
531 * @param {Object} config The config object
535 Roo.bootstrap.Button = function(config){
536 Roo.bootstrap.Button.superclass.constructor.call(this, config);
537 this.weightClass = ["btn-default",
549 * When a butotn is pressed
550 * @param {Roo.bootstrap.Button} this
551 * @param {Roo.EventObject} e
556 * After the button has been toggles
557 * @param {Roo.EventObject} e
558 * @param {boolean} pressed (also available as button.pressed)
564 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
582 preventDefault: true,
591 getAutoCreate : function(){
599 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
600 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
605 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
607 if (this.toggle == true) {
610 cls: 'slider-frame roo-button',
615 'data-off-text':'OFF',
616 cls: 'slider-button',
622 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
623 cfg.cls += ' '+this.weight;
632 cfg["aria-hidden"] = true;
634 cfg.html = "×";
640 if (this.theme==='default') {
641 cfg.cls = 'btn roo-button';
643 //if (this.parentType != 'Navbar') {
644 this.weight = this.weight.length ? this.weight : 'default';
646 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
648 cfg.cls += ' btn-' + this.weight;
650 } else if (this.theme==='glow') {
653 cfg.cls = 'btn-glow roo-button';
655 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
657 cfg.cls += ' ' + this.weight;
663 this.cls += ' inverse';
668 cfg.cls += ' active';
672 cfg.disabled = 'disabled';
676 Roo.log('changing to ul' );
678 this.glyphicon = 'caret';
681 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
683 //gsRoo.log(this.parentType);
684 if (this.parentType === 'Navbar' && !this.parent().bar) {
685 Roo.log('changing to li?');
694 href : this.href || '#'
697 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
698 cfg.cls += ' dropdown';
705 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
707 if (this.glyphicon) {
708 cfg.html = ' ' + cfg.html;
713 cls: 'glyphicon glyphicon-' + this.glyphicon
723 // cfg.cls='btn roo-button';
727 var value = cfg.html;
732 cls: 'glyphicon glyphicon-' + this.glyphicon,
751 cfg.cls += ' dropdown';
752 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
755 if (cfg.tag !== 'a' && this.href !== '') {
756 throw "Tag must be a to set href.";
757 } else if (this.href.length > 0) {
758 cfg.href = this.href;
761 if(this.removeClass){
766 cfg.target = this.target;
771 initEvents: function() {
772 // Roo.log('init events?');
773 // Roo.log(this.el.dom);
776 if (typeof (this.menu) != 'undefined') {
777 this.menu.parentType = this.xtype;
778 this.menu.triggerEl = this.el;
779 this.addxtype(Roo.apply({}, this.menu));
783 if (this.el.hasClass('roo-button')) {
784 this.el.on('click', this.onClick, this);
786 this.el.select('.roo-button').on('click', this.onClick, this);
789 if(this.removeClass){
790 this.el.on('click', this.onClick, this);
793 this.el.enableDisplayMode();
796 onClick : function(e)
803 Roo.log('button on click ');
804 if(this.preventDefault){
807 if (this.pressed === true || this.pressed === false) {
808 this.pressed = !this.pressed;
809 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
810 this.fireEvent('toggle', this, e, this.pressed);
814 this.fireEvent('click', this, e);
818 * Enables this button
822 this.disabled = false;
823 this.el.removeClass('disabled');
827 * Disable this button
831 this.disabled = true;
832 this.el.addClass('disabled');
835 * sets the active state on/off,
836 * @param {Boolean} state (optional) Force a particular state
838 setActive : function(v) {
840 this.el[v ? 'addClass' : 'removeClass']('active');
843 * toggles the current active state
845 toggleActive : function()
847 var active = this.el.hasClass('active');
848 this.setActive(!active);
852 setText : function(str)
854 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
858 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
869 setWeight : function(str)
871 this.el.removeClass(this.weightClass);
872 this.el.addClass('btn-' + str);
886 * @class Roo.bootstrap.Column
887 * @extends Roo.bootstrap.Component
888 * Bootstrap Column class
889 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
890 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
891 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
892 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
893 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
894 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
895 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
896 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
899 * @cfg {Boolean} hidden (true|false) hide the element
900 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
901 * @cfg {String} fa (ban|check|...) font awesome icon
902 * @cfg {Number} fasize (1|2|....) font awsome size
904 * @cfg {String} icon (info-sign|check|...) glyphicon name
906 * @cfg {String} html content of column.
909 * Create a new Column
910 * @param {Object} config The config object
913 Roo.bootstrap.Column = function(config){
914 Roo.bootstrap.Column.superclass.constructor.call(this, config);
917 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
935 getAutoCreate : function(){
936 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
944 ['xs','sm','md','lg'].map(function(size){
945 //Roo.log( size + ':' + settings[size]);
947 if (settings[size+'off'] !== false) {
948 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
951 if (settings[size] === false) {
955 if (!settings[size]) { // 0 = hidden
956 cfg.cls += ' hidden-' + size;
959 cfg.cls += ' col-' + size + '-' + settings[size];
964 cfg.cls += ' hidden';
967 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
968 cfg.cls +=' alert alert-' + this.alert;
972 if (this.html.length) {
973 cfg.html = this.html;
977 if (this.fasize > 1) {
978 fasize = ' fa-' + this.fasize + 'x';
980 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
985 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1004 * @class Roo.bootstrap.Container
1005 * @extends Roo.bootstrap.Component
1006 * Bootstrap Container class
1007 * @cfg {Boolean} jumbotron is it a jumbotron element
1008 * @cfg {String} html content of element
1009 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1010 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
1011 * @cfg {String} header content of header (for panel)
1012 * @cfg {String} footer content of footer (for panel)
1013 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1014 * @cfg {String} tag (header|aside|section) type of HTML tag.
1015 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1016 * @cfg {String} fa font awesome icon
1017 * @cfg {String} icon (info-sign|check|...) glyphicon name
1018 * @cfg {Boolean} hidden (true|false) hide the element
1019 * @cfg {Boolean} expandable (true|false) default false
1020 * @cfg {Boolean} expanded (true|false) default true
1021 * @cfg {String} rheader contet on the right of header
1022 * @cfg {Boolean} clickable (true|false) default false
1026 * Create a new Container
1027 * @param {Object} config The config object
1030 Roo.bootstrap.Container = function(config){
1031 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1037 * After the panel has been expand
1039 * @param {Roo.bootstrap.Container} this
1044 * After the panel has been collapsed
1046 * @param {Roo.bootstrap.Container} this
1051 * When a element is chick
1052 * @param {Roo.bootstrap.Container} this
1053 * @param {Roo.EventObject} e
1059 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1077 getChildContainer : function() {
1083 if (this.panel.length) {
1084 return this.el.select('.panel-body',true).first();
1091 getAutoCreate : function(){
1094 tag : this.tag || 'div',
1098 if (this.jumbotron) {
1099 cfg.cls = 'jumbotron';
1104 // - this is applied by the parent..
1106 // cfg.cls = this.cls + '';
1109 if (this.sticky.length) {
1111 var bd = Roo.get(document.body);
1112 if (!bd.hasClass('bootstrap-sticky')) {
1113 bd.addClass('bootstrap-sticky');
1114 Roo.select('html',true).setStyle('height', '100%');
1117 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1121 if (this.well.length) {
1122 switch (this.well) {
1125 cfg.cls +=' well well-' +this.well;
1134 cfg.cls += ' hidden';
1138 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1139 cfg.cls +=' alert alert-' + this.alert;
1144 if (this.panel.length) {
1145 cfg.cls += ' panel panel-' + this.panel;
1147 if (this.header.length) {
1151 if(this.expandable){
1153 cfg.cls = cfg.cls + ' expandable';
1157 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1165 cls : 'panel-title',
1166 html : (this.expandable ? ' ' : '') + this.header
1170 cls: 'panel-header-right',
1176 cls : 'panel-heading',
1177 style : this.expandable ? 'cursor: pointer' : '',
1185 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1190 if (this.footer.length) {
1192 cls : 'panel-footer',
1201 body.html = this.html || cfg.html;
1202 // prefix with the icons..
1204 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1207 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1212 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1213 cfg.cls = 'container';
1219 initEvents: function()
1221 if(this.expandable){
1222 var headerEl = this.headerEl();
1225 headerEl.on('click', this.onToggleClick, this);
1230 this.el.on('click', this.onClick, this);
1235 onToggleClick : function()
1237 var headerEl = this.headerEl();
1253 if(this.fireEvent('expand', this)) {
1255 this.expanded = true;
1257 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1259 this.el.select('.panel-body',true).first().removeClass('hide');
1261 var toggleEl = this.toggleEl();
1267 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1272 collapse : function()
1274 if(this.fireEvent('collapse', this)) {
1276 this.expanded = false;
1278 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1279 this.el.select('.panel-body',true).first().addClass('hide');
1281 var toggleEl = this.toggleEl();
1287 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1291 toggleEl : function()
1293 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1297 return this.el.select('.panel-heading .fa',true).first();
1300 headerEl : function()
1302 if(!this.el || !this.panel.length || !this.header.length){
1306 return this.el.select('.panel-heading',true).first()
1311 if(!this.el || !this.panel.length){
1315 return this.el.select('.panel-body',true).first()
1318 titleEl : function()
1320 if(!this.el || !this.panel.length || !this.header.length){
1324 return this.el.select('.panel-title',true).first();
1327 setTitle : function(v)
1329 var titleEl = this.titleEl();
1335 titleEl.dom.innerHTML = v;
1338 getTitle : function()
1341 var titleEl = this.titleEl();
1347 return titleEl.dom.innerHTML;
1350 setRightTitle : function(v)
1352 var t = this.el.select('.panel-header-right',true).first();
1358 t.dom.innerHTML = v;
1361 onClick : function(e)
1365 this.fireEvent('click', this, e);
1379 * @class Roo.bootstrap.Img
1380 * @extends Roo.bootstrap.Component
1381 * Bootstrap Img class
1382 * @cfg {Boolean} imgResponsive false | true
1383 * @cfg {String} border rounded | circle | thumbnail
1384 * @cfg {String} src image source
1385 * @cfg {String} alt image alternative text
1386 * @cfg {String} href a tag href
1387 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1388 * @cfg {String} xsUrl xs image source
1389 * @cfg {String} smUrl sm image source
1390 * @cfg {String} mdUrl md image source
1391 * @cfg {String} lgUrl lg image source
1394 * Create a new Input
1395 * @param {Object} config The config object
1398 Roo.bootstrap.Img = function(config){
1399 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1405 * The img click event for the img.
1406 * @param {Roo.EventObject} e
1412 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1414 imgResponsive: true,
1424 getAutoCreate : function()
1426 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1427 return this.createSingleImg();
1432 cls: 'roo-image-responsive-group',
1437 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1439 if(!_this[size + 'Url']){
1445 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1446 html: _this.html || cfg.html,
1447 src: _this[size + 'Url']
1450 img.cls += ' roo-image-responsive-' + size;
1452 var s = ['xs', 'sm', 'md', 'lg'];
1454 s.splice(s.indexOf(size), 1);
1456 Roo.each(s, function(ss){
1457 img.cls += ' hidden-' + ss;
1460 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1461 cfg.cls += ' img-' + _this.border;
1465 cfg.alt = _this.alt;
1478 a.target = _this.target;
1482 cfg.cn.push((_this.href) ? a : img);
1489 createSingleImg : function()
1493 cls: (this.imgResponsive) ? 'img-responsive' : '',
1495 src : 'about:blank' // just incase src get's set to undefined?!?
1498 cfg.html = this.html || cfg.html;
1500 cfg.src = this.src || cfg.src;
1502 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1503 cfg.cls += ' img-' + this.border;
1520 a.target = this.target;
1525 return (this.href) ? a : cfg;
1528 initEvents: function()
1531 this.el.on('click', this.onClick, this);
1536 onClick : function(e)
1538 Roo.log('img onclick');
1539 this.fireEvent('click', this, e);
1542 * Sets the url of the image - used to update it
1543 * @param {String} url the url of the image
1546 setSrc : function(url)
1550 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1551 this.el.dom.src = url;
1555 this.el.select('img', true).first().dom.src = url;
1571 * @class Roo.bootstrap.Link
1572 * @extends Roo.bootstrap.Component
1573 * Bootstrap Link Class
1574 * @cfg {String} alt image alternative text
1575 * @cfg {String} href a tag href
1576 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1577 * @cfg {String} html the content of the link.
1578 * @cfg {String} anchor name for the anchor link
1579 * @cfg {String} fa - favicon
1581 * @cfg {Boolean} preventDefault (true | false) default false
1585 * Create a new Input
1586 * @param {Object} config The config object
1589 Roo.bootstrap.Link = function(config){
1590 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1596 * The img click event for the img.
1597 * @param {Roo.EventObject} e
1603 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1607 preventDefault: false,
1613 getAutoCreate : function()
1615 var html = this.html || '';
1617 if (this.fa !== false) {
1618 html = '<i class="fa fa-' + this.fa + '"></i>';
1623 // anchor's do not require html/href...
1624 if (this.anchor === false) {
1626 cfg.href = this.href || '#';
1628 cfg.name = this.anchor;
1629 if (this.html !== false || this.fa !== false) {
1632 if (this.href !== false) {
1633 cfg.href = this.href;
1637 if(this.alt !== false){
1642 if(this.target !== false) {
1643 cfg.target = this.target;
1649 initEvents: function() {
1651 if(!this.href || this.preventDefault){
1652 this.el.on('click', this.onClick, this);
1656 onClick : function(e)
1658 if(this.preventDefault){
1661 //Roo.log('img onclick');
1662 this.fireEvent('click', this, e);
1675 * @class Roo.bootstrap.Header
1676 * @extends Roo.bootstrap.Component
1677 * Bootstrap Header class
1678 * @cfg {String} html content of header
1679 * @cfg {Number} level (1|2|3|4|5|6) default 1
1682 * Create a new Header
1683 * @param {Object} config The config object
1687 Roo.bootstrap.Header = function(config){
1688 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1691 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1699 getAutoCreate : function(){
1704 tag: 'h' + (1 *this.level),
1705 html: this.html || ''
1717 * Ext JS Library 1.1.1
1718 * Copyright(c) 2006-2007, Ext JS, LLC.
1720 * Originally Released Under LGPL - original licence link has changed is not relivant.
1723 * <script type="text/javascript">
1727 * @class Roo.bootstrap.MenuMgr
1728 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1731 Roo.bootstrap.MenuMgr = function(){
1732 var menus, active, groups = {}, attached = false, lastShow = new Date();
1734 // private - called when first menu is created
1737 active = new Roo.util.MixedCollection();
1738 Roo.get(document).addKeyListener(27, function(){
1739 if(active.length > 0){
1747 if(active && active.length > 0){
1748 var c = active.clone();
1758 if(active.length < 1){
1759 Roo.get(document).un("mouseup", onMouseDown);
1767 var last = active.last();
1768 lastShow = new Date();
1771 Roo.get(document).on("mouseup", onMouseDown);
1776 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1777 m.parentMenu.activeChild = m;
1778 }else if(last && last.isVisible()){
1779 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1784 function onBeforeHide(m){
1786 m.activeChild.hide();
1788 if(m.autoHideTimer){
1789 clearTimeout(m.autoHideTimer);
1790 delete m.autoHideTimer;
1795 function onBeforeShow(m){
1796 var pm = m.parentMenu;
1797 if(!pm && !m.allowOtherMenus){
1799 }else if(pm && pm.activeChild && active != m){
1800 pm.activeChild.hide();
1804 // private this should really trigger on mouseup..
1805 function onMouseDown(e){
1806 Roo.log("on Mouse Up");
1808 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1809 Roo.log("MenuManager hideAll");
1818 function onBeforeCheck(mi, state){
1820 var g = groups[mi.group];
1821 for(var i = 0, l = g.length; i < l; i++){
1823 g[i].setChecked(false);
1832 * Hides all menus that are currently visible
1834 hideAll : function(){
1839 register : function(menu){
1843 menus[menu.id] = menu;
1844 menu.on("beforehide", onBeforeHide);
1845 menu.on("hide", onHide);
1846 menu.on("beforeshow", onBeforeShow);
1847 menu.on("show", onShow);
1849 if(g && menu.events["checkchange"]){
1853 groups[g].push(menu);
1854 menu.on("checkchange", onCheck);
1859 * Returns a {@link Roo.menu.Menu} object
1860 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1861 * be used to generate and return a new Menu instance.
1863 get : function(menu){
1864 if(typeof menu == "string"){ // menu id
1866 }else if(menu.events){ // menu instance
1869 /*else if(typeof menu.length == 'number'){ // array of menu items?
1870 return new Roo.bootstrap.Menu({items:menu});
1871 }else{ // otherwise, must be a config
1872 return new Roo.bootstrap.Menu(menu);
1879 unregister : function(menu){
1880 delete menus[menu.id];
1881 menu.un("beforehide", onBeforeHide);
1882 menu.un("hide", onHide);
1883 menu.un("beforeshow", onBeforeShow);
1884 menu.un("show", onShow);
1886 if(g && menu.events["checkchange"]){
1887 groups[g].remove(menu);
1888 menu.un("checkchange", onCheck);
1893 registerCheckable : function(menuItem){
1894 var g = menuItem.group;
1899 groups[g].push(menuItem);
1900 menuItem.on("beforecheckchange", onBeforeCheck);
1905 unregisterCheckable : function(menuItem){
1906 var g = menuItem.group;
1908 groups[g].remove(menuItem);
1909 menuItem.un("beforecheckchange", onBeforeCheck);
1921 * @class Roo.bootstrap.Menu
1922 * @extends Roo.bootstrap.Component
1923 * Bootstrap Menu class - container for MenuItems
1924 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1925 * @cfg {bool} hidden if the menu should be hidden when rendered.
1926 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1927 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1931 * @param {Object} config The config object
1935 Roo.bootstrap.Menu = function(config){
1936 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1937 if (this.registerMenu && this.type != 'treeview') {
1938 Roo.bootstrap.MenuMgr.register(this);
1943 * Fires before this menu is displayed
1944 * @param {Roo.menu.Menu} this
1949 * Fires before this menu is hidden
1950 * @param {Roo.menu.Menu} this
1955 * Fires after this menu is displayed
1956 * @param {Roo.menu.Menu} this
1961 * Fires after this menu is hidden
1962 * @param {Roo.menu.Menu} this
1967 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1968 * @param {Roo.menu.Menu} this
1969 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1970 * @param {Roo.EventObject} e
1975 * Fires when the mouse is hovering over this menu
1976 * @param {Roo.menu.Menu} this
1977 * @param {Roo.EventObject} e
1978 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1983 * Fires when the mouse exits this menu
1984 * @param {Roo.menu.Menu} this
1985 * @param {Roo.EventObject} e
1986 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1991 * Fires when a menu item contained in this menu is clicked
1992 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1993 * @param {Roo.EventObject} e
1997 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2000 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2004 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2007 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2009 registerMenu : true,
2011 menuItems :false, // stores the menu items..
2021 getChildContainer : function() {
2025 getAutoCreate : function(){
2027 //if (['right'].indexOf(this.align)!==-1) {
2028 // cfg.cn[1].cls += ' pull-right'
2034 cls : 'dropdown-menu' ,
2035 style : 'z-index:1000'
2039 if (this.type === 'submenu') {
2040 cfg.cls = 'submenu active';
2042 if (this.type === 'treeview') {
2043 cfg.cls = 'treeview-menu';
2048 initEvents : function() {
2050 // Roo.log("ADD event");
2051 // Roo.log(this.triggerEl.dom);
2053 this.triggerEl.on('click', this.onTriggerClick, this);
2055 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2057 this.triggerEl.addClass('dropdown-toggle');
2060 this.el.on('touchstart' , this.onTouch, this);
2062 this.el.on('click' , this.onClick, this);
2064 this.el.on("mouseover", this.onMouseOver, this);
2065 this.el.on("mouseout", this.onMouseOut, this);
2069 findTargetItem : function(e)
2071 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2075 //Roo.log(t); Roo.log(t.id);
2077 //Roo.log(this.menuitems);
2078 return this.menuitems.get(t.id);
2080 //return this.items.get(t.menuItemId);
2086 onTouch : function(e)
2088 Roo.log("menu.onTouch");
2089 //e.stopEvent(); this make the user popdown broken
2093 onClick : function(e)
2095 Roo.log("menu.onClick");
2097 var t = this.findTargetItem(e);
2098 if(!t || t.isContainer){
2103 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2104 if(t == this.activeItem && t.shouldDeactivate(e)){
2105 this.activeItem.deactivate();
2106 delete this.activeItem;
2110 this.setActiveItem(t, true);
2118 Roo.log('pass click event');
2122 this.fireEvent("click", this, t, e);
2126 if(!t.href.length || t.href == '#'){
2127 (function() { _this.hide(); }).defer(100);
2132 onMouseOver : function(e){
2133 var t = this.findTargetItem(e);
2136 // if(t.canActivate && !t.disabled){
2137 // this.setActiveItem(t, true);
2141 this.fireEvent("mouseover", this, e, t);
2143 isVisible : function(){
2144 return !this.hidden;
2146 onMouseOut : function(e){
2147 var t = this.findTargetItem(e);
2150 // if(t == this.activeItem && t.shouldDeactivate(e)){
2151 // this.activeItem.deactivate();
2152 // delete this.activeItem;
2155 this.fireEvent("mouseout", this, e, t);
2160 * Displays this menu relative to another element
2161 * @param {String/HTMLElement/Roo.Element} element The element to align to
2162 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2163 * the element (defaults to this.defaultAlign)
2164 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2166 show : function(el, pos, parentMenu){
2167 this.parentMenu = parentMenu;
2171 this.fireEvent("beforeshow", this);
2172 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2175 * Displays this menu at a specific xy position
2176 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2177 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2179 showAt : function(xy, parentMenu, /* private: */_e){
2180 this.parentMenu = parentMenu;
2185 this.fireEvent("beforeshow", this);
2186 //xy = this.el.adjustForConstraints(xy);
2190 this.hideMenuItems();
2191 this.hidden = false;
2192 this.triggerEl.addClass('open');
2194 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2195 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2198 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2203 this.fireEvent("show", this);
2209 this.doFocus.defer(50, this);
2213 doFocus : function(){
2215 this.focusEl.focus();
2220 * Hides this menu and optionally all parent menus
2221 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2223 hide : function(deep)
2226 this.hideMenuItems();
2227 if(this.el && this.isVisible()){
2228 this.fireEvent("beforehide", this);
2229 if(this.activeItem){
2230 this.activeItem.deactivate();
2231 this.activeItem = null;
2233 this.triggerEl.removeClass('open');;
2235 this.fireEvent("hide", this);
2237 if(deep === true && this.parentMenu){
2238 this.parentMenu.hide(true);
2242 onTriggerClick : function(e)
2244 Roo.log('trigger click');
2246 var target = e.getTarget();
2248 Roo.log(target.nodeName.toLowerCase());
2250 if(target.nodeName.toLowerCase() === 'i'){
2256 onTriggerPress : function(e)
2258 Roo.log('trigger press');
2259 //Roo.log(e.getTarget());
2260 // Roo.log(this.triggerEl.dom);
2262 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2263 var pel = Roo.get(e.getTarget());
2264 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2265 Roo.log('is treeview or dropdown?');
2269 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2273 if (this.isVisible()) {
2278 this.show(this.triggerEl, false, false);
2281 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2288 hideMenuItems : function()
2290 Roo.log("hide Menu Items");
2294 //$(backdrop).remove()
2295 this.el.select('.open',true).each(function(aa) {
2297 aa.removeClass('open');
2298 //var parent = getParent($(this))
2299 //var relatedTarget = { relatedTarget: this }
2301 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2302 //if (e.isDefaultPrevented()) return
2303 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2306 addxtypeChild : function (tree, cntr) {
2307 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2309 this.menuitems.add(comp);
2330 * @class Roo.bootstrap.MenuItem
2331 * @extends Roo.bootstrap.Component
2332 * Bootstrap MenuItem class
2333 * @cfg {String} html the menu label
2334 * @cfg {String} href the link
2335 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2336 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2337 * @cfg {Boolean} active used on sidebars to highlight active itesm
2338 * @cfg {String} fa favicon to show on left of menu item.
2339 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2343 * Create a new MenuItem
2344 * @param {Object} config The config object
2348 Roo.bootstrap.MenuItem = function(config){
2349 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2354 * The raw click event for the entire grid.
2355 * @param {Roo.bootstrap.MenuItem} this
2356 * @param {Roo.EventObject} e
2362 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2366 preventDefault: false,
2367 isContainer : false,
2371 getAutoCreate : function(){
2373 if(this.isContainer){
2376 cls: 'dropdown-menu-item'
2390 if (this.fa !== false) {
2393 cls : 'fa fa-' + this.fa
2402 cls: 'dropdown-menu-item',
2405 if (this.parent().type == 'treeview') {
2406 cfg.cls = 'treeview-menu';
2409 cfg.cls += ' active';
2414 anc.href = this.href || cfg.cn[0].href ;
2415 ctag.html = this.html || cfg.cn[0].html ;
2419 initEvents: function()
2421 if (this.parent().type == 'treeview') {
2422 this.el.select('a').on('click', this.onClick, this);
2426 this.menu.parentType = this.xtype;
2427 this.menu.triggerEl = this.el;
2428 this.menu = this.addxtype(Roo.apply({}, this.menu));
2432 onClick : function(e)
2434 Roo.log('item on click ');
2436 if(this.preventDefault){
2439 //this.parent().hideMenuItems();
2441 this.fireEvent('click', this, e);
2460 * @class Roo.bootstrap.MenuSeparator
2461 * @extends Roo.bootstrap.Component
2462 * Bootstrap MenuSeparator class
2465 * Create a new MenuItem
2466 * @param {Object} config The config object
2470 Roo.bootstrap.MenuSeparator = function(config){
2471 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2474 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2476 getAutoCreate : function(){
2495 * @class Roo.bootstrap.Modal
2496 * @extends Roo.bootstrap.Component
2497 * Bootstrap Modal class
2498 * @cfg {String} title Title of dialog
2499 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2500 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2501 * @cfg {Boolean} specificTitle default false
2502 * @cfg {Array} buttons Array of buttons or standard button set..
2503 * @cfg {String} buttonPosition (left|right|center) default right
2504 * @cfg {Boolean} animate default true
2505 * @cfg {Boolean} allow_close default true
2506 * @cfg {Boolean} fitwindow default false
2507 * @cfg {String} size (sm|lg) default empty
2511 * Create a new Modal Dialog
2512 * @param {Object} config The config object
2515 Roo.bootstrap.Modal = function(config){
2516 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2521 * The raw btnclick event for the button
2522 * @param {Roo.EventObject} e
2527 * Fire when dialog resize
2528 * @param {Roo.bootstrap.Modal} this
2529 * @param {Roo.EventObject} e
2533 this.buttons = this.buttons || [];
2536 this.tmpl = Roo.factory(this.tmpl);
2541 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2543 title : 'test dialog',
2553 specificTitle: false,
2555 buttonPosition: 'right',
2574 onRender : function(ct, position)
2576 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2579 var cfg = Roo.apply({}, this.getAutoCreate());
2582 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2584 //if (!cfg.name.length) {
2588 cfg.cls += ' ' + this.cls;
2591 cfg.style = this.style;
2593 this.el = Roo.get(document.body).createChild(cfg, position);
2595 //var type = this.el.dom.type;
2598 if(this.tabIndex !== undefined){
2599 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2602 this.dialogEl = this.el.select('.modal-dialog',true).first();
2603 this.bodyEl = this.el.select('.modal-body',true).first();
2604 this.closeEl = this.el.select('.modal-header .close', true).first();
2605 this.headerEl = this.el.select('.modal-header',true).first();
2606 this.titleEl = this.el.select('.modal-title',true).first();
2607 this.footerEl = this.el.select('.modal-footer',true).first();
2609 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2610 this.maskEl.enableDisplayMode("block");
2612 //this.el.addClass("x-dlg-modal");
2614 if (this.buttons.length) {
2615 Roo.each(this.buttons, function(bb) {
2616 var b = Roo.apply({}, bb);
2617 b.xns = b.xns || Roo.bootstrap;
2618 b.xtype = b.xtype || 'Button';
2619 if (typeof(b.listeners) == 'undefined') {
2620 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2623 var btn = Roo.factory(b);
2625 btn.render(this.el.select('.modal-footer div').first());
2629 // render the children.
2632 if(typeof(this.items) != 'undefined'){
2633 var items = this.items;
2636 for(var i =0;i < items.length;i++) {
2637 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2641 this.items = nitems;
2643 // where are these used - they used to be body/close/footer
2647 //this.el.addClass([this.fieldClass, this.cls]);
2651 getAutoCreate : function(){
2656 html : this.html || ''
2661 cls : 'modal-title',
2665 if(this.specificTitle){
2671 if (this.allow_close) {
2683 if(this.size.length){
2684 size = 'modal-' + this.size;
2689 style : 'display: none',
2692 cls: "modal-dialog " + size,
2695 cls : "modal-content",
2698 cls : 'modal-header',
2703 cls : 'modal-footer',
2707 cls: 'btn-' + this.buttonPosition
2724 modal.cls += ' fade';
2730 getChildContainer : function() {
2735 getButtonContainer : function() {
2736 return this.el.select('.modal-footer div',true).first();
2739 initEvents : function()
2741 if (this.allow_close) {
2742 this.closeEl.on('click', this.hide, this);
2744 Roo.EventManager.onWindowResize(this.resize, this, true);
2751 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2752 if (this.fitwindow) {
2753 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2754 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2759 setSize : function(w,h)
2769 if (!this.rendered) {
2773 this.el.setStyle('display', 'block');
2775 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2778 this.el.addClass('in');
2781 this.el.addClass('in');
2785 // not sure how we can show data in here..
2787 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2790 Roo.get(document.body).addClass("x-body-masked");
2792 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2793 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2798 this.fireEvent('show', this);
2800 // set zindex here - otherwise it appears to be ignored...
2801 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2804 this.items.forEach( function(e) {
2805 e.layout ? e.layout() : false;
2813 if(this.fireEvent("beforehide", this) !== false){
2815 Roo.get(document.body).removeClass("x-body-masked");
2816 this.el.removeClass('in');
2817 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2819 if(this.animate){ // why
2821 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2823 this.el.setStyle('display', 'none');
2825 this.fireEvent('hide', this);
2829 addButton : function(str, cb)
2833 var b = Roo.apply({}, { html : str } );
2834 b.xns = b.xns || Roo.bootstrap;
2835 b.xtype = b.xtype || 'Button';
2836 if (typeof(b.listeners) == 'undefined') {
2837 b.listeners = { click : cb.createDelegate(this) };
2840 var btn = Roo.factory(b);
2842 btn.render(this.el.select('.modal-footer div').first());
2848 setDefaultButton : function(btn)
2850 //this.el.select('.modal-footer').()
2854 resizeTo: function(w,h)
2858 this.dialogEl.setWidth(w);
2859 if (this.diff === false) {
2860 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2863 this.bodyEl.setHeight(h-this.diff);
2865 this.fireEvent('resize', this);
2868 setContentSize : function(w, h)
2872 onButtonClick: function(btn,e)
2875 this.fireEvent('btnclick', btn.name, e);
2878 * Set the title of the Dialog
2879 * @param {String} str new Title
2881 setTitle: function(str) {
2882 this.titleEl.dom.innerHTML = str;
2885 * Set the body of the Dialog
2886 * @param {String} str new Title
2888 setBody: function(str) {
2889 this.bodyEl.dom.innerHTML = str;
2892 * Set the body of the Dialog using the template
2893 * @param {Obj} data - apply this data to the template and replace the body contents.
2895 applyBody: function(obj)
2898 Roo.log("Error - using apply Body without a template");
2901 this.tmpl.overwrite(this.bodyEl, obj);
2907 Roo.apply(Roo.bootstrap.Modal, {
2909 * Button config that displays a single OK button
2918 * Button config that displays Yes and No buttons
2934 * Button config that displays OK and Cancel buttons
2949 * Button config that displays Yes, No and Cancel buttons
2973 * messagebox - can be used as a replace
2977 * @class Roo.MessageBox
2978 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2982 Roo.Msg.alert('Status', 'Changes saved successfully.');
2984 // Prompt for user data:
2985 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2987 // process text value...
2991 // Show a dialog using config options:
2993 title:'Save Changes?',
2994 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2995 buttons: Roo.Msg.YESNOCANCEL,
3002 Roo.bootstrap.MessageBox = function(){
3003 var dlg, opt, mask, waitTimer;
3004 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3005 var buttons, activeTextEl, bwidth;
3009 var handleButton = function(button){
3011 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3015 var handleHide = function(){
3017 dlg.el.removeClass(opt.cls);
3020 // Roo.TaskMgr.stop(waitTimer);
3021 // waitTimer = null;
3026 var updateButtons = function(b){
3029 buttons["ok"].hide();
3030 buttons["cancel"].hide();
3031 buttons["yes"].hide();
3032 buttons["no"].hide();
3033 //dlg.footer.dom.style.display = 'none';
3036 dlg.footerEl.dom.style.display = '';
3037 for(var k in buttons){
3038 if(typeof buttons[k] != "function"){
3041 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3042 width += buttons[k].el.getWidth()+15;
3052 var handleEsc = function(d, k, e){
3053 if(opt && opt.closable !== false){
3063 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3064 * @return {Roo.BasicDialog} The BasicDialog element
3066 getDialog : function(){
3068 dlg = new Roo.bootstrap.Modal( {
3071 //constraintoviewport:false,
3073 //collapsible : false,
3078 //buttonAlign:"center",
3079 closeClick : function(){
3080 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3083 handleButton("cancel");
3088 dlg.on("hide", handleHide);
3090 //dlg.addKeyListener(27, handleEsc);
3092 this.buttons = buttons;
3093 var bt = this.buttonText;
3094 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3095 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3096 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3097 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3099 bodyEl = dlg.bodyEl.createChild({
3101 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3102 '<textarea class="roo-mb-textarea"></textarea>' +
3103 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3105 msgEl = bodyEl.dom.firstChild;
3106 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3107 textboxEl.enableDisplayMode();
3108 textboxEl.addKeyListener([10,13], function(){
3109 if(dlg.isVisible() && opt && opt.buttons){
3112 }else if(opt.buttons.yes){
3113 handleButton("yes");
3117 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3118 textareaEl.enableDisplayMode();
3119 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3120 progressEl.enableDisplayMode();
3122 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3123 //var pf = progressEl.dom.firstChild;
3125 //pp = Roo.get(pf.firstChild);
3126 //pp.setHeight(pf.offsetHeight);
3134 * Updates the message box body text
3135 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3136 * the XHTML-compliant non-breaking space character '&#160;')
3137 * @return {Roo.MessageBox} This message box
3139 updateText : function(text)
3141 if(!dlg.isVisible() && !opt.width){
3142 dlg.dialogEl.setWidth(this.maxWidth);
3143 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3145 msgEl.innerHTML = text || ' ';
3147 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3148 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3150 Math.min(opt.width || cw , this.maxWidth),
3151 Math.max(opt.minWidth || this.minWidth, bwidth)
3154 activeTextEl.setWidth(w);
3156 if(dlg.isVisible()){
3157 dlg.fixedcenter = false;
3159 // to big, make it scroll. = But as usual stupid IE does not support
3162 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3163 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3164 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3166 bodyEl.dom.style.height = '';
3167 bodyEl.dom.style.overflowY = '';
3170 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3172 bodyEl.dom.style.overflowX = '';
3175 dlg.setContentSize(w, bodyEl.getHeight());
3176 if(dlg.isVisible()){
3177 dlg.fixedcenter = true;
3183 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3184 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3185 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3186 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3187 * @return {Roo.MessageBox} This message box
3189 updateProgress : function(value, text){
3191 this.updateText(text);
3193 if (pp) { // weird bug on my firefox - for some reason this is not defined
3194 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3200 * Returns true if the message box is currently displayed
3201 * @return {Boolean} True if the message box is visible, else false
3203 isVisible : function(){
3204 return dlg && dlg.isVisible();
3208 * Hides the message box if it is displayed
3211 if(this.isVisible()){
3217 * Displays a new message box, or reinitializes an existing message box, based on the config options
3218 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3219 * The following config object properties are supported:
3221 Property Type Description
3222 ---------- --------------- ------------------------------------------------------------------------------------
3223 animEl String/Element An id or Element from which the message box should animate as it opens and
3224 closes (defaults to undefined)
3225 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3226 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3227 closable Boolean False to hide the top-right close button (defaults to true). Note that
3228 progress and wait dialogs will ignore this property and always hide the
3229 close button as they can only be closed programmatically.
3230 cls String A custom CSS class to apply to the message box element
3231 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3232 displayed (defaults to 75)
3233 fn Function A callback function to execute after closing the dialog. The arguments to the
3234 function will be btn (the name of the button that was clicked, if applicable,
3235 e.g. "ok"), and text (the value of the active text field, if applicable).
3236 Progress and wait dialogs will ignore this option since they do not respond to
3237 user actions and can only be closed programmatically, so any required function
3238 should be called by the same code after it closes the dialog.
3239 icon String A CSS class that provides a background image to be used as an icon for
3240 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3241 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3242 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3243 modal Boolean False to allow user interaction with the page while the message box is
3244 displayed (defaults to true)
3245 msg String A string that will replace the existing message box body text (defaults
3246 to the XHTML-compliant non-breaking space character ' ')
3247 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3248 progress Boolean True to display a progress bar (defaults to false)
3249 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3250 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3251 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3252 title String The title text
3253 value String The string value to set into the active textbox element if displayed
3254 wait Boolean True to display a progress bar (defaults to false)
3255 width Number The width of the dialog in pixels
3262 msg: 'Please enter your address:',
3264 buttons: Roo.MessageBox.OKCANCEL,
3267 animEl: 'addAddressBtn'
3270 * @param {Object} config Configuration options
3271 * @return {Roo.MessageBox} This message box
3273 show : function(options)
3276 // this causes nightmares if you show one dialog after another
3277 // especially on callbacks..
3279 if(this.isVisible()){
3282 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3283 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3284 Roo.log("New Dialog Message:" + options.msg )
3285 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3286 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3289 var d = this.getDialog();
3291 d.setTitle(opt.title || " ");
3292 d.closeEl.setDisplayed(opt.closable !== false);
3293 activeTextEl = textboxEl;
3294 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3299 textareaEl.setHeight(typeof opt.multiline == "number" ?
3300 opt.multiline : this.defaultTextHeight);
3301 activeTextEl = textareaEl;
3310 progressEl.setDisplayed(opt.progress === true);
3311 this.updateProgress(0);
3312 activeTextEl.dom.value = opt.value || "";
3314 dlg.setDefaultButton(activeTextEl);
3316 var bs = opt.buttons;
3320 }else if(bs && bs.yes){
3321 db = buttons["yes"];
3323 dlg.setDefaultButton(db);
3325 bwidth = updateButtons(opt.buttons);
3326 this.updateText(opt.msg);
3328 d.el.addClass(opt.cls);
3330 d.proxyDrag = opt.proxyDrag === true;
3331 d.modal = opt.modal !== false;
3332 d.mask = opt.modal !== false ? mask : false;
3334 // force it to the end of the z-index stack so it gets a cursor in FF
3335 document.body.appendChild(dlg.el.dom);
3336 d.animateTarget = null;
3337 d.show(options.animEl);
3343 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3344 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3345 * and closing the message box when the process is complete.
3346 * @param {String} title The title bar text
3347 * @param {String} msg The message box body text
3348 * @return {Roo.MessageBox} This message box
3350 progress : function(title, msg){
3357 minWidth: this.minProgressWidth,
3364 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3365 * If a callback function is passed it will be called after the user clicks the button, and the
3366 * id of the button that was clicked will be passed as the only parameter to the callback
3367 * (could also be the top-right close button).
3368 * @param {String} title The title bar text
3369 * @param {String} msg The message box body text
3370 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3371 * @param {Object} scope (optional) The scope of the callback function
3372 * @return {Roo.MessageBox} This message box
3374 alert : function(title, msg, fn, scope)
3389 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3390 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3391 * You are responsible for closing the message box when the process is complete.
3392 * @param {String} msg The message box body text
3393 * @param {String} title (optional) The title bar text
3394 * @return {Roo.MessageBox} This message box
3396 wait : function(msg, title){
3407 waitTimer = Roo.TaskMgr.start({
3409 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3417 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3418 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3419 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3420 * @param {String} title The title bar text
3421 * @param {String} msg The message box body text
3422 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3423 * @param {Object} scope (optional) The scope of the callback function
3424 * @return {Roo.MessageBox} This message box
3426 confirm : function(title, msg, fn, scope){
3430 buttons: this.YESNO,
3439 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3440 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3441 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3442 * (could also be the top-right close button) and the text that was entered will be passed as the two
3443 * parameters to the callback.
3444 * @param {String} title The title bar text
3445 * @param {String} msg The message box body text
3446 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3447 * @param {Object} scope (optional) The scope of the callback function
3448 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3449 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3450 * @return {Roo.MessageBox} This message box
3452 prompt : function(title, msg, fn, scope, multiline){
3456 buttons: this.OKCANCEL,
3461 multiline: multiline,
3468 * Button config that displays a single OK button
3473 * Button config that displays Yes and No buttons
3476 YESNO : {yes:true, no:true},
3478 * Button config that displays OK and Cancel buttons
3481 OKCANCEL : {ok:true, cancel:true},
3483 * Button config that displays Yes, No and Cancel buttons
3486 YESNOCANCEL : {yes:true, no:true, cancel:true},
3489 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3492 defaultTextHeight : 75,
3494 * The maximum width in pixels of the message box (defaults to 600)
3499 * The minimum width in pixels of the message box (defaults to 100)
3504 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3505 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3508 minProgressWidth : 250,
3510 * An object containing the default button text strings that can be overriden for localized language support.
3511 * Supported properties are: ok, cancel, yes and no.
3512 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3525 * Shorthand for {@link Roo.MessageBox}
3527 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3528 Roo.Msg = Roo.Msg || Roo.MessageBox;
3537 * @class Roo.bootstrap.Navbar
3538 * @extends Roo.bootstrap.Component
3539 * Bootstrap Navbar class
3542 * Create a new Navbar
3543 * @param {Object} config The config object
3547 Roo.bootstrap.Navbar = function(config){
3548 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3552 * @event beforetoggle
3553 * Fire before toggle the menu
3554 * @param {Roo.EventObject} e
3556 "beforetoggle" : true
3560 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3569 getAutoCreate : function(){
3572 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3576 initEvents :function ()
3578 //Roo.log(this.el.select('.navbar-toggle',true));
3579 this.el.select('.navbar-toggle',true).on('click', function() {
3580 if(this.fireEvent('beforetoggle', this) !== false){
3581 this.el.select('.navbar-collapse',true).toggleClass('in');
3591 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3593 var size = this.el.getSize();
3594 this.maskEl.setSize(size.width, size.height);
3595 this.maskEl.enableDisplayMode("block");
3604 getChildContainer : function()
3606 if (this.el.select('.collapse').getCount()) {
3607 return this.el.select('.collapse',true).first();
3640 * @class Roo.bootstrap.NavSimplebar
3641 * @extends Roo.bootstrap.Navbar
3642 * Bootstrap Sidebar class
3644 * @cfg {Boolean} inverse is inverted color
3646 * @cfg {String} type (nav | pills | tabs)
3647 * @cfg {Boolean} arrangement stacked | justified
3648 * @cfg {String} align (left | right) alignment
3650 * @cfg {Boolean} main (true|false) main nav bar? default false
3651 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3653 * @cfg {String} tag (header|footer|nav|div) default is nav
3659 * Create a new Sidebar
3660 * @param {Object} config The config object
3664 Roo.bootstrap.NavSimplebar = function(config){
3665 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3668 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3684 getAutoCreate : function(){
3688 tag : this.tag || 'div',
3701 this.type = this.type || 'nav';
3702 if (['tabs','pills'].indexOf(this.type)!==-1) {
3703 cfg.cn[0].cls += ' nav-' + this.type
3707 if (this.type!=='nav') {
3708 Roo.log('nav type must be nav/tabs/pills')
3710 cfg.cn[0].cls += ' navbar-nav'
3716 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3717 cfg.cn[0].cls += ' nav-' + this.arrangement;
3721 if (this.align === 'right') {
3722 cfg.cn[0].cls += ' navbar-right';
3726 cfg.cls += ' navbar-inverse';
3753 * @class Roo.bootstrap.NavHeaderbar
3754 * @extends Roo.bootstrap.NavSimplebar
3755 * Bootstrap Sidebar class
3757 * @cfg {String} brand what is brand
3758 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3759 * @cfg {String} brand_href href of the brand
3760 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3761 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3762 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3763 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3766 * Create a new Sidebar
3767 * @param {Object} config The config object
3771 Roo.bootstrap.NavHeaderbar = function(config){
3772 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3776 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3783 desktopCenter : false,
3786 getAutoCreate : function(){
3789 tag: this.nav || 'nav',
3796 if (this.desktopCenter) {
3797 cn.push({cls : 'container', cn : []});
3804 cls: 'navbar-header',
3809 cls: 'navbar-toggle',
3810 'data-toggle': 'collapse',
3815 html: 'Toggle navigation'
3837 cls: 'collapse navbar-collapse',
3841 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3843 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3844 cfg.cls += ' navbar-' + this.position;
3846 // tag can override this..
3848 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3851 if (this.brand !== '') {
3854 href: this.brand_href ? this.brand_href : '#',
3855 cls: 'navbar-brand',
3863 cfg.cls += ' main-nav';
3871 getHeaderChildContainer : function()
3873 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3874 return this.el.select('.navbar-header',true).first();
3877 return this.getChildContainer();
3881 initEvents : function()
3883 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3885 if (this.autohide) {
3890 Roo.get(document).on('scroll',function(e) {
3891 var ns = Roo.get(document).getScroll().top;
3892 var os = prevScroll;
3896 ft.removeClass('slideDown');
3897 ft.addClass('slideUp');
3900 ft.removeClass('slideUp');
3901 ft.addClass('slideDown');
3922 * @class Roo.bootstrap.NavSidebar
3923 * @extends Roo.bootstrap.Navbar
3924 * Bootstrap Sidebar class
3927 * Create a new Sidebar
3928 * @param {Object} config The config object
3932 Roo.bootstrap.NavSidebar = function(config){
3933 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3936 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3938 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3940 getAutoCreate : function(){
3945 cls: 'sidebar sidebar-nav'
3967 * @class Roo.bootstrap.NavGroup
3968 * @extends Roo.bootstrap.Component
3969 * Bootstrap NavGroup class
3970 * @cfg {String} align (left|right)
3971 * @cfg {Boolean} inverse
3972 * @cfg {String} type (nav|pills|tab) default nav
3973 * @cfg {String} navId - reference Id for navbar.
3977 * Create a new nav group
3978 * @param {Object} config The config object
3981 Roo.bootstrap.NavGroup = function(config){
3982 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3985 Roo.bootstrap.NavGroup.register(this);
3989 * Fires when the active item changes
3990 * @param {Roo.bootstrap.NavGroup} this
3991 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3992 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3999 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4010 getAutoCreate : function()
4012 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4019 if (['tabs','pills'].indexOf(this.type)!==-1) {
4020 cfg.cls += ' nav-' + this.type
4022 if (this.type!=='nav') {
4023 Roo.log('nav type must be nav/tabs/pills')
4025 cfg.cls += ' navbar-nav'
4028 if (this.parent().sidebar) {
4031 cls: 'dashboard-menu sidebar-menu'
4037 if (this.form === true) {
4043 if (this.align === 'right') {
4044 cfg.cls += ' navbar-right';
4046 cfg.cls += ' navbar-left';
4050 if (this.align === 'right') {
4051 cfg.cls += ' navbar-right';
4055 cfg.cls += ' navbar-inverse';
4063 * sets the active Navigation item
4064 * @param {Roo.bootstrap.NavItem} the new current navitem
4066 setActiveItem : function(item)
4069 Roo.each(this.navItems, function(v){
4074 v.setActive(false, true);
4081 item.setActive(true, true);
4082 this.fireEvent('changed', this, item, prev);
4087 * gets the active Navigation item
4088 * @return {Roo.bootstrap.NavItem} the current navitem
4090 getActive : function()
4094 Roo.each(this.navItems, function(v){
4105 indexOfNav : function()
4109 Roo.each(this.navItems, function(v,i){
4120 * adds a Navigation item
4121 * @param {Roo.bootstrap.NavItem} the navitem to add
4123 addItem : function(cfg)
4125 var cn = new Roo.bootstrap.NavItem(cfg);
4127 cn.parentId = this.id;
4128 cn.onRender(this.el, null);
4132 * register a Navigation item
4133 * @param {Roo.bootstrap.NavItem} the navitem to add
4135 register : function(item)
4137 this.navItems.push( item);
4138 item.navId = this.navId;
4143 * clear all the Navigation item
4146 clearAll : function()
4149 this.el.dom.innerHTML = '';
4152 getNavItem: function(tabId)
4155 Roo.each(this.navItems, function(e) {
4156 if (e.tabId == tabId) {
4166 setActiveNext : function()
4168 var i = this.indexOfNav(this.getActive());
4169 if (i > this.navItems.length) {
4172 this.setActiveItem(this.navItems[i+1]);
4174 setActivePrev : function()
4176 var i = this.indexOfNav(this.getActive());
4180 this.setActiveItem(this.navItems[i-1]);
4182 clearWasActive : function(except) {
4183 Roo.each(this.navItems, function(e) {
4184 if (e.tabId != except.tabId && e.was_active) {
4185 e.was_active = false;
4192 getWasActive : function ()
4195 Roo.each(this.navItems, function(e) {
4210 Roo.apply(Roo.bootstrap.NavGroup, {
4214 * register a Navigation Group
4215 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4217 register : function(navgrp)
4219 this.groups[navgrp.navId] = navgrp;
4223 * fetch a Navigation Group based on the navigation ID
4224 * @param {string} the navgroup to add
4225 * @returns {Roo.bootstrap.NavGroup} the navgroup
4227 get: function(navId) {
4228 if (typeof(this.groups[navId]) == 'undefined') {
4230 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4232 return this.groups[navId] ;
4247 * @class Roo.bootstrap.NavItem
4248 * @extends Roo.bootstrap.Component
4249 * Bootstrap Navbar.NavItem class
4250 * @cfg {String} href link to
4251 * @cfg {String} html content of button
4252 * @cfg {String} badge text inside badge
4253 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4254 * @cfg {String} glyphicon name of glyphicon
4255 * @cfg {String} icon name of font awesome icon
4256 * @cfg {Boolean} active Is item active
4257 * @cfg {Boolean} disabled Is item disabled
4259 * @cfg {Boolean} preventDefault (true | false) default false
4260 * @cfg {String} tabId the tab that this item activates.
4261 * @cfg {String} tagtype (a|span) render as a href or span?
4262 * @cfg {Boolean} animateRef (true|false) link to element default false
4265 * Create a new Navbar Item
4266 * @param {Object} config The config object
4268 Roo.bootstrap.NavItem = function(config){
4269 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4274 * The raw click event for the entire grid.
4275 * @param {Roo.EventObject} e
4280 * Fires when the active item active state changes
4281 * @param {Roo.bootstrap.NavItem} this
4282 * @param {boolean} state the new state
4288 * Fires when scroll to element
4289 * @param {Roo.bootstrap.NavItem} this
4290 * @param {Object} options
4291 * @param {Roo.EventObject} e
4299 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4307 preventDefault : false,
4314 getAutoCreate : function(){
4323 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4325 if (this.disabled) {
4326 cfg.cls += ' disabled';
4329 if (this.href || this.html || this.glyphicon || this.icon) {
4333 href : this.href || "#",
4334 html: this.html || ''
4339 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4342 if(this.glyphicon) {
4343 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4348 cfg.cn[0].html += " <span class='caret'></span>";
4352 if (this.badge !== '') {
4354 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4362 initEvents: function()
4364 if (typeof (this.menu) != 'undefined') {
4365 this.menu.parentType = this.xtype;
4366 this.menu.triggerEl = this.el;
4367 this.menu = this.addxtype(Roo.apply({}, this.menu));
4370 this.el.select('a',true).on('click', this.onClick, this);
4372 if(this.tagtype == 'span'){
4373 this.el.select('span',true).on('click', this.onClick, this);
4376 // at this point parent should be available..
4377 this.parent().register(this);
4380 onClick : function(e)
4382 if (e.getTarget('.dropdown-menu-item')) {
4383 // did you click on a menu itemm.... - then don't trigger onclick..
4388 this.preventDefault ||
4391 Roo.log("NavItem - prevent Default?");
4395 if (this.disabled) {
4399 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4400 if (tg && tg.transition) {
4401 Roo.log("waiting for the transitionend");
4407 //Roo.log("fire event clicked");
4408 if(this.fireEvent('click', this, e) === false){
4412 if(this.tagtype == 'span'){
4416 //Roo.log(this.href);
4417 var ael = this.el.select('a',true).first();
4420 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4421 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4422 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4423 return; // ignore... - it's a 'hash' to another page.
4425 Roo.log("NavItem - prevent Default?");
4427 this.scrollToElement(e);
4431 var p = this.parent();
4433 if (['tabs','pills'].indexOf(p.type)!==-1) {
4434 if (typeof(p.setActiveItem) !== 'undefined') {
4435 p.setActiveItem(this);
4439 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4440 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4441 // remove the collapsed menu expand...
4442 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4446 isActive: function () {
4449 setActive : function(state, fire, is_was_active)
4451 if (this.active && !state && this.navId) {
4452 this.was_active = true;
4453 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4455 nv.clearWasActive(this);
4459 this.active = state;
4462 this.el.removeClass('active');
4463 } else if (!this.el.hasClass('active')) {
4464 this.el.addClass('active');
4467 this.fireEvent('changed', this, state);
4470 // show a panel if it's registered and related..
4472 if (!this.navId || !this.tabId || !state || is_was_active) {
4476 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4480 var pan = tg.getPanelByName(this.tabId);
4484 // if we can not flip to new panel - go back to old nav highlight..
4485 if (false == tg.showPanel(pan)) {
4486 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4488 var onav = nv.getWasActive();
4490 onav.setActive(true, false, true);
4499 // this should not be here...
4500 setDisabled : function(state)
4502 this.disabled = state;
4504 this.el.removeClass('disabled');
4505 } else if (!this.el.hasClass('disabled')) {
4506 this.el.addClass('disabled');
4512 * Fetch the element to display the tooltip on.
4513 * @return {Roo.Element} defaults to this.el
4515 tooltipEl : function()
4517 return this.el.select('' + this.tagtype + '', true).first();
4520 scrollToElement : function(e)
4522 var c = document.body;
4525 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4527 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4528 c = document.documentElement;
4531 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4537 var o = target.calcOffsetsTo(c);
4544 this.fireEvent('scrollto', this, options, e);
4546 Roo.get(c).scrollTo('top', options.value, true);
4559 * <span> icon </span>
4560 * <span> text </span>
4561 * <span>badge </span>
4565 * @class Roo.bootstrap.NavSidebarItem
4566 * @extends Roo.bootstrap.NavItem
4567 * Bootstrap Navbar.NavSidebarItem class
4568 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4569 * {bool} open is the menu open
4571 * Create a new Navbar Button
4572 * @param {Object} config The config object
4574 Roo.bootstrap.NavSidebarItem = function(config){
4575 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4580 * The raw click event for the entire grid.
4581 * @param {Roo.EventObject} e
4586 * Fires when the active item active state changes
4587 * @param {Roo.bootstrap.NavSidebarItem} this
4588 * @param {boolean} state the new state
4596 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4598 badgeWeight : 'default',
4602 getAutoCreate : function(){
4607 href : this.href || '#',
4619 html : this.html || ''
4624 cfg.cls += ' active';
4627 if (this.disabled) {
4628 cfg.cls += ' disabled';
4631 cfg.cls += ' open x-open';
4634 if (this.glyphicon || this.icon) {
4635 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4636 a.cn.push({ tag : 'i', cls : c }) ;
4641 if (this.badge !== '') {
4643 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4647 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4648 a.cls += 'dropdown-toggle treeview' ;
4656 initEvents : function()
4658 if (typeof (this.menu) != 'undefined') {
4659 this.menu.parentType = this.xtype;
4660 this.menu.triggerEl = this.el;
4661 this.menu = this.addxtype(Roo.apply({}, this.menu));
4664 this.el.on('click', this.onClick, this);
4667 if(this.badge !== ''){
4669 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4674 onClick : function(e)
4681 if(this.preventDefault){
4685 this.fireEvent('click', this);
4688 disable : function()
4690 this.setDisabled(true);
4695 this.setDisabled(false);
4698 setDisabled : function(state)
4700 if(this.disabled == state){
4704 this.disabled = state;
4707 this.el.addClass('disabled');
4711 this.el.removeClass('disabled');
4716 setActive : function(state)
4718 if(this.active == state){
4722 this.active = state;
4725 this.el.addClass('active');
4729 this.el.removeClass('active');
4734 isActive: function ()
4739 setBadge : function(str)
4745 this.badgeEl.dom.innerHTML = str;
4762 * @class Roo.bootstrap.Row
4763 * @extends Roo.bootstrap.Component
4764 * Bootstrap Row class (contains columns...)
4768 * @param {Object} config The config object
4771 Roo.bootstrap.Row = function(config){
4772 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4775 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4777 getAutoCreate : function(){
4796 * @class Roo.bootstrap.Element
4797 * @extends Roo.bootstrap.Component
4798 * Bootstrap Element class
4799 * @cfg {String} html contents of the element
4800 * @cfg {String} tag tag of the element
4801 * @cfg {String} cls class of the element
4802 * @cfg {Boolean} preventDefault (true|false) default false
4803 * @cfg {Boolean} clickable (true|false) default false
4806 * Create a new Element
4807 * @param {Object} config The config object
4810 Roo.bootstrap.Element = function(config){
4811 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4817 * When a element is chick
4818 * @param {Roo.bootstrap.Element} this
4819 * @param {Roo.EventObject} e
4825 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4830 preventDefault: false,
4833 getAutoCreate : function(){
4844 initEvents: function()
4846 Roo.bootstrap.Element.superclass.initEvents.call(this);
4849 this.el.on('click', this.onClick, this);
4854 onClick : function(e)
4856 if(this.preventDefault){
4860 this.fireEvent('click', this, e);
4863 getValue : function()
4865 return this.el.dom.innerHTML;
4868 setValue : function(value)
4870 this.el.dom.innerHTML = value;
4885 * @class Roo.bootstrap.Pagination
4886 * @extends Roo.bootstrap.Component
4887 * Bootstrap Pagination class
4888 * @cfg {String} size xs | sm | md | lg
4889 * @cfg {Boolean} inverse false | true
4892 * Create a new Pagination
4893 * @param {Object} config The config object
4896 Roo.bootstrap.Pagination = function(config){
4897 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4900 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4906 getAutoCreate : function(){
4912 cfg.cls += ' inverse';
4918 cfg.cls += " " + this.cls;
4936 * @class Roo.bootstrap.PaginationItem
4937 * @extends Roo.bootstrap.Component
4938 * Bootstrap PaginationItem class
4939 * @cfg {String} html text
4940 * @cfg {String} href the link
4941 * @cfg {Boolean} preventDefault (true | false) default true
4942 * @cfg {Boolean} active (true | false) default false
4943 * @cfg {Boolean} disabled default false
4947 * Create a new PaginationItem
4948 * @param {Object} config The config object
4952 Roo.bootstrap.PaginationItem = function(config){
4953 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4958 * The raw click event for the entire grid.
4959 * @param {Roo.EventObject} e
4965 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4969 preventDefault: true,
4974 getAutoCreate : function(){
4980 href : this.href ? this.href : '#',
4981 html : this.html ? this.html : ''
4991 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4995 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5001 initEvents: function() {
5003 this.el.on('click', this.onClick, this);
5006 onClick : function(e)
5008 Roo.log('PaginationItem on click ');
5009 if(this.preventDefault){
5017 this.fireEvent('click', this, e);
5033 * @class Roo.bootstrap.Slider
5034 * @extends Roo.bootstrap.Component
5035 * Bootstrap Slider class
5038 * Create a new Slider
5039 * @param {Object} config The config object
5042 Roo.bootstrap.Slider = function(config){
5043 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5046 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5048 getAutoCreate : function(){
5052 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5056 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5068 * Ext JS Library 1.1.1
5069 * Copyright(c) 2006-2007, Ext JS, LLC.
5071 * Originally Released Under LGPL - original licence link has changed is not relivant.
5074 * <script type="text/javascript">
5079 * @class Roo.grid.ColumnModel
5080 * @extends Roo.util.Observable
5081 * This is the default implementation of a ColumnModel used by the Grid. It defines
5082 * the columns in the grid.
5085 var colModel = new Roo.grid.ColumnModel([
5086 {header: "Ticker", width: 60, sortable: true, locked: true},
5087 {header: "Company Name", width: 150, sortable: true},
5088 {header: "Market Cap.", width: 100, sortable: true},
5089 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5090 {header: "Employees", width: 100, sortable: true, resizable: false}
5095 * The config options listed for this class are options which may appear in each
5096 * individual column definition.
5097 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5099 * @param {Object} config An Array of column config objects. See this class's
5100 * config objects for details.
5102 Roo.grid.ColumnModel = function(config){
5104 * The config passed into the constructor
5106 this.config = config;
5109 // if no id, create one
5110 // if the column does not have a dataIndex mapping,
5111 // map it to the order it is in the config
5112 for(var i = 0, len = config.length; i < len; i++){
5114 if(typeof c.dataIndex == "undefined"){
5117 if(typeof c.renderer == "string"){
5118 c.renderer = Roo.util.Format[c.renderer];
5120 if(typeof c.id == "undefined"){
5123 if(c.editor && c.editor.xtype){
5124 c.editor = Roo.factory(c.editor, Roo.grid);
5126 if(c.editor && c.editor.isFormField){
5127 c.editor = new Roo.grid.GridEditor(c.editor);
5129 this.lookup[c.id] = c;
5133 * The width of columns which have no width specified (defaults to 100)
5136 this.defaultWidth = 100;
5139 * Default sortable of columns which have no sortable specified (defaults to false)
5142 this.defaultSortable = false;
5146 * @event widthchange
5147 * Fires when the width of a column changes.
5148 * @param {ColumnModel} this
5149 * @param {Number} columnIndex The column index
5150 * @param {Number} newWidth The new width
5152 "widthchange": true,
5154 * @event headerchange
5155 * Fires when the text of a header changes.
5156 * @param {ColumnModel} this
5157 * @param {Number} columnIndex The column index
5158 * @param {Number} newText The new header text
5160 "headerchange": true,
5162 * @event hiddenchange
5163 * Fires when a column is hidden or "unhidden".
5164 * @param {ColumnModel} this
5165 * @param {Number} columnIndex The column index
5166 * @param {Boolean} hidden true if hidden, false otherwise
5168 "hiddenchange": true,
5170 * @event columnmoved
5171 * Fires when a column is moved.
5172 * @param {ColumnModel} this
5173 * @param {Number} oldIndex
5174 * @param {Number} newIndex
5176 "columnmoved" : true,
5178 * @event columlockchange
5179 * Fires when a column's locked state is changed
5180 * @param {ColumnModel} this
5181 * @param {Number} colIndex
5182 * @param {Boolean} locked true if locked
5184 "columnlockchange" : true
5186 Roo.grid.ColumnModel.superclass.constructor.call(this);
5188 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5190 * @cfg {String} header The header text to display in the Grid view.
5193 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5194 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5195 * specified, the column's index is used as an index into the Record's data Array.
5198 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5199 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5202 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5203 * Defaults to the value of the {@link #defaultSortable} property.
5204 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5207 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5210 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5213 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5216 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5219 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5220 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5221 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5222 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5225 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5228 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5231 * @cfg {String} cursor (Optional)
5234 * @cfg {String} tooltip (Optional)
5237 * @cfg {Number} xs (Optional)
5240 * @cfg {Number} sm (Optional)
5243 * @cfg {Number} md (Optional)
5246 * @cfg {Number} lg (Optional)
5249 * Returns the id of the column at the specified index.
5250 * @param {Number} index The column index
5251 * @return {String} the id
5253 getColumnId : function(index){
5254 return this.config[index].id;
5258 * Returns the column for a specified id.
5259 * @param {String} id The column id
5260 * @return {Object} the column
5262 getColumnById : function(id){
5263 return this.lookup[id];
5268 * Returns the column for a specified dataIndex.
5269 * @param {String} dataIndex The column dataIndex
5270 * @return {Object|Boolean} the column or false if not found
5272 getColumnByDataIndex: function(dataIndex){
5273 var index = this.findColumnIndex(dataIndex);
5274 return index > -1 ? this.config[index] : false;
5278 * Returns the index for a specified column id.
5279 * @param {String} id The column id
5280 * @return {Number} the index, or -1 if not found
5282 getIndexById : function(id){
5283 for(var i = 0, len = this.config.length; i < len; i++){
5284 if(this.config[i].id == id){
5292 * Returns the index for a specified column dataIndex.
5293 * @param {String} dataIndex The column dataIndex
5294 * @return {Number} the index, or -1 if not found
5297 findColumnIndex : function(dataIndex){
5298 for(var i = 0, len = this.config.length; i < len; i++){
5299 if(this.config[i].dataIndex == dataIndex){
5307 moveColumn : function(oldIndex, newIndex){
5308 var c = this.config[oldIndex];
5309 this.config.splice(oldIndex, 1);
5310 this.config.splice(newIndex, 0, c);
5311 this.dataMap = null;
5312 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5315 isLocked : function(colIndex){
5316 return this.config[colIndex].locked === true;
5319 setLocked : function(colIndex, value, suppressEvent){
5320 if(this.isLocked(colIndex) == value){
5323 this.config[colIndex].locked = value;
5325 this.fireEvent("columnlockchange", this, colIndex, value);
5329 getTotalLockedWidth : function(){
5331 for(var i = 0; i < this.config.length; i++){
5332 if(this.isLocked(i) && !this.isHidden(i)){
5333 this.totalWidth += this.getColumnWidth(i);
5339 getLockedCount : function(){
5340 for(var i = 0, len = this.config.length; i < len; i++){
5341 if(!this.isLocked(i)){
5346 return this.config.length;
5350 * Returns the number of columns.
5353 getColumnCount : function(visibleOnly){
5354 if(visibleOnly === true){
5356 for(var i = 0, len = this.config.length; i < len; i++){
5357 if(!this.isHidden(i)){
5363 return this.config.length;
5367 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5368 * @param {Function} fn
5369 * @param {Object} scope (optional)
5370 * @return {Array} result
5372 getColumnsBy : function(fn, scope){
5374 for(var i = 0, len = this.config.length; i < len; i++){
5375 var c = this.config[i];
5376 if(fn.call(scope||this, c, i) === true){
5384 * Returns true if the specified column is sortable.
5385 * @param {Number} col The column index
5388 isSortable : function(col){
5389 if(typeof this.config[col].sortable == "undefined"){
5390 return this.defaultSortable;
5392 return this.config[col].sortable;
5396 * Returns the rendering (formatting) function defined for the column.
5397 * @param {Number} col The column index.
5398 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5400 getRenderer : function(col){
5401 if(!this.config[col].renderer){
5402 return Roo.grid.ColumnModel.defaultRenderer;
5404 return this.config[col].renderer;
5408 * Sets the rendering (formatting) function for a column.
5409 * @param {Number} col The column index
5410 * @param {Function} fn The function to use to process the cell's raw data
5411 * to return HTML markup for the grid view. The render function is called with
5412 * the following parameters:<ul>
5413 * <li>Data value.</li>
5414 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5415 * <li>css A CSS style string to apply to the table cell.</li>
5416 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5417 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5418 * <li>Row index</li>
5419 * <li>Column index</li>
5420 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5422 setRenderer : function(col, fn){
5423 this.config[col].renderer = fn;
5427 * Returns the width for the specified column.
5428 * @param {Number} col The column index
5431 getColumnWidth : function(col){
5432 return this.config[col].width * 1 || this.defaultWidth;
5436 * Sets the width for a column.
5437 * @param {Number} col The column index
5438 * @param {Number} width The new width
5440 setColumnWidth : function(col, width, suppressEvent){
5441 this.config[col].width = width;
5442 this.totalWidth = null;
5444 this.fireEvent("widthchange", this, col, width);
5449 * Returns the total width of all columns.
5450 * @param {Boolean} includeHidden True to include hidden column widths
5453 getTotalWidth : function(includeHidden){
5454 if(!this.totalWidth){
5455 this.totalWidth = 0;
5456 for(var i = 0, len = this.config.length; i < len; i++){
5457 if(includeHidden || !this.isHidden(i)){
5458 this.totalWidth += this.getColumnWidth(i);
5462 return this.totalWidth;
5466 * Returns the header for the specified column.
5467 * @param {Number} col The column index
5470 getColumnHeader : function(col){
5471 return this.config[col].header;
5475 * Sets the header for a column.
5476 * @param {Number} col The column index
5477 * @param {String} header The new header
5479 setColumnHeader : function(col, header){
5480 this.config[col].header = header;
5481 this.fireEvent("headerchange", this, col, header);
5485 * Returns the tooltip for the specified column.
5486 * @param {Number} col The column index
5489 getColumnTooltip : function(col){
5490 return this.config[col].tooltip;
5493 * Sets the tooltip for a column.
5494 * @param {Number} col The column index
5495 * @param {String} tooltip The new tooltip
5497 setColumnTooltip : function(col, tooltip){
5498 this.config[col].tooltip = tooltip;
5502 * Returns the dataIndex for the specified column.
5503 * @param {Number} col The column index
5506 getDataIndex : function(col){
5507 return this.config[col].dataIndex;
5511 * Sets the dataIndex for a column.
5512 * @param {Number} col The column index
5513 * @param {Number} dataIndex The new dataIndex
5515 setDataIndex : function(col, dataIndex){
5516 this.config[col].dataIndex = dataIndex;
5522 * Returns true if the cell is editable.
5523 * @param {Number} colIndex The column index
5524 * @param {Number} rowIndex The row index - this is nto actually used..?
5527 isCellEditable : function(colIndex, rowIndex){
5528 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5532 * Returns the editor defined for the cell/column.
5533 * return false or null to disable editing.
5534 * @param {Number} colIndex The column index
5535 * @param {Number} rowIndex The row index
5538 getCellEditor : function(colIndex, rowIndex){
5539 return this.config[colIndex].editor;
5543 * Sets if a column is editable.
5544 * @param {Number} col The column index
5545 * @param {Boolean} editable True if the column is editable
5547 setEditable : function(col, editable){
5548 this.config[col].editable = editable;
5553 * Returns true if the column is hidden.
5554 * @param {Number} colIndex The column index
5557 isHidden : function(colIndex){
5558 return this.config[colIndex].hidden;
5563 * Returns true if the column width cannot be changed
5565 isFixed : function(colIndex){
5566 return this.config[colIndex].fixed;
5570 * Returns true if the column can be resized
5573 isResizable : function(colIndex){
5574 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5577 * Sets if a column is hidden.
5578 * @param {Number} colIndex The column index
5579 * @param {Boolean} hidden True if the column is hidden
5581 setHidden : function(colIndex, hidden){
5582 this.config[colIndex].hidden = hidden;
5583 this.totalWidth = null;
5584 this.fireEvent("hiddenchange", this, colIndex, hidden);
5588 * Sets the editor for a column.
5589 * @param {Number} col The column index
5590 * @param {Object} editor The editor object
5592 setEditor : function(col, editor){
5593 this.config[col].editor = editor;
5597 Roo.grid.ColumnModel.defaultRenderer = function(value)
5599 if(typeof value == "object") {
5602 if(typeof value == "string" && value.length < 1){
5606 return String.format("{0}", value);
5609 // Alias for backwards compatibility
5610 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5613 * Ext JS Library 1.1.1
5614 * Copyright(c) 2006-2007, Ext JS, LLC.
5616 * Originally Released Under LGPL - original licence link has changed is not relivant.
5619 * <script type="text/javascript">
5623 * @class Roo.LoadMask
5624 * A simple utility class for generically masking elements while loading data. If the element being masked has
5625 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5626 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5627 * element's UpdateManager load indicator and will be destroyed after the initial load.
5629 * Create a new LoadMask
5630 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5631 * @param {Object} config The config object
5633 Roo.LoadMask = function(el, config){
5634 this.el = Roo.get(el);
5635 Roo.apply(this, config);
5637 this.store.on('beforeload', this.onBeforeLoad, this);
5638 this.store.on('load', this.onLoad, this);
5639 this.store.on('loadexception', this.onLoadException, this);
5640 this.removeMask = false;
5642 var um = this.el.getUpdateManager();
5643 um.showLoadIndicator = false; // disable the default indicator
5644 um.on('beforeupdate', this.onBeforeLoad, this);
5645 um.on('update', this.onLoad, this);
5646 um.on('failure', this.onLoad, this);
5647 this.removeMask = true;
5651 Roo.LoadMask.prototype = {
5653 * @cfg {Boolean} removeMask
5654 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5655 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5659 * The text to display in a centered loading message box (defaults to 'Loading...')
5663 * @cfg {String} msgCls
5664 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5666 msgCls : 'x-mask-loading',
5669 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5675 * Disables the mask to prevent it from being displayed
5677 disable : function(){
5678 this.disabled = true;
5682 * Enables the mask so that it can be displayed
5684 enable : function(){
5685 this.disabled = false;
5688 onLoadException : function()
5692 if (typeof(arguments[3]) != 'undefined') {
5693 Roo.MessageBox.alert("Error loading",arguments[3]);
5697 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5698 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5705 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5710 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5714 onBeforeLoad : function(){
5716 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5721 destroy : function(){
5723 this.store.un('beforeload', this.onBeforeLoad, this);
5724 this.store.un('load', this.onLoad, this);
5725 this.store.un('loadexception', this.onLoadException, this);
5727 var um = this.el.getUpdateManager();
5728 um.un('beforeupdate', this.onBeforeLoad, this);
5729 um.un('update', this.onLoad, this);
5730 um.un('failure', this.onLoad, this);
5741 * @class Roo.bootstrap.Table
5742 * @extends Roo.bootstrap.Component
5743 * Bootstrap Table class
5744 * @cfg {String} cls table class
5745 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5746 * @cfg {String} bgcolor Specifies the background color for a table
5747 * @cfg {Number} border Specifies whether the table cells should have borders or not
5748 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5749 * @cfg {Number} cellspacing Specifies the space between cells
5750 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5751 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5752 * @cfg {String} sortable Specifies that the table should be sortable
5753 * @cfg {String} summary Specifies a summary of the content of a table
5754 * @cfg {Number} width Specifies the width of a table
5755 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5757 * @cfg {boolean} striped Should the rows be alternative striped
5758 * @cfg {boolean} bordered Add borders to the table
5759 * @cfg {boolean} hover Add hover highlighting
5760 * @cfg {boolean} condensed Format condensed
5761 * @cfg {boolean} responsive Format condensed
5762 * @cfg {Boolean} loadMask (true|false) default false
5763 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5764 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5765 * @cfg {Boolean} rowSelection (true|false) default false
5766 * @cfg {Boolean} cellSelection (true|false) default false
5767 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5768 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5769 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5773 * Create a new Table
5774 * @param {Object} config The config object
5777 Roo.bootstrap.Table = function(config){
5778 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5783 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5784 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5785 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5786 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5788 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5790 this.sm.grid = this;
5791 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5792 this.sm = this.selModel;
5793 this.sm.xmodule = this.xmodule || false;
5796 if (this.cm && typeof(this.cm.config) == 'undefined') {
5797 this.colModel = new Roo.grid.ColumnModel(this.cm);
5798 this.cm = this.colModel;
5799 this.cm.xmodule = this.xmodule || false;
5802 this.store= Roo.factory(this.store, Roo.data);
5803 this.ds = this.store;
5804 this.ds.xmodule = this.xmodule || false;
5807 if (this.footer && this.store) {
5808 this.footer.dataSource = this.ds;
5809 this.footer = Roo.factory(this.footer);
5816 * Fires when a cell is clicked
5817 * @param {Roo.bootstrap.Table} this
5818 * @param {Roo.Element} el
5819 * @param {Number} rowIndex
5820 * @param {Number} columnIndex
5821 * @param {Roo.EventObject} e
5825 * @event celldblclick
5826 * Fires when a cell is double clicked
5827 * @param {Roo.bootstrap.Table} this
5828 * @param {Roo.Element} el
5829 * @param {Number} rowIndex
5830 * @param {Number} columnIndex
5831 * @param {Roo.EventObject} e
5833 "celldblclick" : true,
5836 * Fires when a row is clicked
5837 * @param {Roo.bootstrap.Table} this
5838 * @param {Roo.Element} el
5839 * @param {Number} rowIndex
5840 * @param {Roo.EventObject} e
5844 * @event rowdblclick
5845 * Fires when a row is double clicked
5846 * @param {Roo.bootstrap.Table} this
5847 * @param {Roo.Element} el
5848 * @param {Number} rowIndex
5849 * @param {Roo.EventObject} e
5851 "rowdblclick" : true,
5854 * Fires when a mouseover occur
5855 * @param {Roo.bootstrap.Table} this
5856 * @param {Roo.Element} el
5857 * @param {Number} rowIndex
5858 * @param {Number} columnIndex
5859 * @param {Roo.EventObject} e
5864 * Fires when a mouseout occur
5865 * @param {Roo.bootstrap.Table} this
5866 * @param {Roo.Element} el
5867 * @param {Number} rowIndex
5868 * @param {Number} columnIndex
5869 * @param {Roo.EventObject} e
5874 * Fires when a row is rendered, so you can change add a style to it.
5875 * @param {Roo.bootstrap.Table} this
5876 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5880 * @event rowsrendered
5881 * Fires when all the rows have been rendered
5882 * @param {Roo.bootstrap.Table} this
5884 'rowsrendered' : true,
5886 * @event contextmenu
5887 * The raw contextmenu event for the entire grid.
5888 * @param {Roo.EventObject} e
5890 "contextmenu" : true,
5892 * @event rowcontextmenu
5893 * Fires when a row is right clicked
5894 * @param {Roo.bootstrap.Table} this
5895 * @param {Number} rowIndex
5896 * @param {Roo.EventObject} e
5898 "rowcontextmenu" : true,
5900 * @event cellcontextmenu
5901 * Fires when a cell is right clicked
5902 * @param {Roo.bootstrap.Table} this
5903 * @param {Number} rowIndex
5904 * @param {Number} cellIndex
5905 * @param {Roo.EventObject} e
5907 "cellcontextmenu" : true,
5909 * @event headercontextmenu
5910 * Fires when a header is right clicked
5911 * @param {Roo.bootstrap.Table} this
5912 * @param {Number} columnIndex
5913 * @param {Roo.EventObject} e
5915 "headercontextmenu" : true
5919 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5945 rowSelection : false,
5946 cellSelection : false,
5949 // Roo.Element - the tbody
5951 // Roo.Element - thead element
5954 container: false, // used by gridpanel...
5958 getAutoCreate : function()
5960 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5967 if (this.scrollBody) {
5968 cfg.cls += ' table-body-fixed';
5971 cfg.cls += ' table-striped';
5975 cfg.cls += ' table-hover';
5977 if (this.bordered) {
5978 cfg.cls += ' table-bordered';
5980 if (this.condensed) {
5981 cfg.cls += ' table-condensed';
5983 if (this.responsive) {
5984 cfg.cls += ' table-responsive';
5988 cfg.cls+= ' ' +this.cls;
5991 // this lot should be simplifed...
5994 cfg.align=this.align;
5997 cfg.bgcolor=this.bgcolor;
6000 cfg.border=this.border;
6002 if (this.cellpadding) {
6003 cfg.cellpadding=this.cellpadding;
6005 if (this.cellspacing) {
6006 cfg.cellspacing=this.cellspacing;
6009 cfg.frame=this.frame;
6012 cfg.rules=this.rules;
6014 if (this.sortable) {
6015 cfg.sortable=this.sortable;
6018 cfg.summary=this.summary;
6021 cfg.width=this.width;
6024 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6027 if(this.store || this.cm){
6028 if(this.headerShow){
6029 cfg.cn.push(this.renderHeader());
6032 cfg.cn.push(this.renderBody());
6034 if(this.footerShow){
6035 cfg.cn.push(this.renderFooter());
6037 // where does this come from?
6038 //cfg.cls+= ' TableGrid';
6041 return { cn : [ cfg ] };
6044 initEvents : function()
6046 if(!this.store || !this.cm){
6049 if (this.selModel) {
6050 this.selModel.initEvents();
6054 //Roo.log('initEvents with ds!!!!');
6056 this.mainBody = this.el.select('tbody', true).first();
6057 this.mainHead = this.el.select('thead', true).first();
6064 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6065 e.on('click', _this.sort, _this);
6068 this.mainBody.on("click", this.onClick, this);
6069 this.mainBody.on("dblclick", this.onDblClick, this);
6071 // why is this done????? = it breaks dialogs??
6072 //this.parent().el.setStyle('position', 'relative');
6076 this.footer.parentId = this.id;
6077 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6080 this.el.select('tfoot tr td').first().addClass('hide');
6084 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6086 this.store.on('load', this.onLoad, this);
6087 this.store.on('beforeload', this.onBeforeLoad, this);
6088 this.store.on('update', this.onUpdate, this);
6089 this.store.on('add', this.onAdd, this);
6090 this.store.on("clear", this.clear, this);
6092 this.el.on("contextmenu", this.onContextMenu, this);
6094 this.mainBody.on('scroll', this.onBodyScroll, this);
6099 onContextMenu : function(e, t)
6101 this.processEvent("contextmenu", e);
6104 processEvent : function(name, e)
6106 if (name != 'touchstart' ) {
6107 this.fireEvent(name, e);
6110 var t = e.getTarget();
6112 var cell = Roo.get(t);
6118 if(cell.findParent('tfoot', false, true)){
6122 if(cell.findParent('thead', false, true)){
6124 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6125 cell = Roo.get(t).findParent('th', false, true);
6127 Roo.log("failed to find th in thead?");
6128 Roo.log(e.getTarget());
6133 var cellIndex = cell.dom.cellIndex;
6135 var ename = name == 'touchstart' ? 'click' : name;
6136 this.fireEvent("header" + ename, this, cellIndex, e);
6141 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6142 cell = Roo.get(t).findParent('td', false, true);
6144 Roo.log("failed to find th in tbody?");
6145 Roo.log(e.getTarget());
6150 var row = cell.findParent('tr', false, true);
6151 var cellIndex = cell.dom.cellIndex;
6152 var rowIndex = row.dom.rowIndex - 1;
6156 this.fireEvent("row" + name, this, rowIndex, e);
6160 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6166 onMouseover : function(e, el)
6168 var cell = Roo.get(el);
6174 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6175 cell = cell.findParent('td', false, true);
6178 var row = cell.findParent('tr', false, true);
6179 var cellIndex = cell.dom.cellIndex;
6180 var rowIndex = row.dom.rowIndex - 1; // start from 0
6182 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6186 onMouseout : function(e, el)
6188 var cell = Roo.get(el);
6194 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6195 cell = cell.findParent('td', false, true);
6198 var row = cell.findParent('tr', false, true);
6199 var cellIndex = cell.dom.cellIndex;
6200 var rowIndex = row.dom.rowIndex - 1; // start from 0
6202 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6206 onClick : function(e, el)
6208 var cell = Roo.get(el);
6210 if(!cell || (!this.cellSelection && !this.rowSelection)){
6214 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6215 cell = cell.findParent('td', false, true);
6218 if(!cell || typeof(cell) == 'undefined'){
6222 var row = cell.findParent('tr', false, true);
6224 if(!row || typeof(row) == 'undefined'){
6228 var cellIndex = cell.dom.cellIndex;
6229 var rowIndex = this.getRowIndex(row);
6231 // why??? - should these not be based on SelectionModel?
6232 if(this.cellSelection){
6233 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6236 if(this.rowSelection){
6237 this.fireEvent('rowclick', this, row, rowIndex, e);
6243 onDblClick : function(e,el)
6245 var cell = Roo.get(el);
6247 if(!cell || (!this.cellSelection && !this.rowSelection)){
6251 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6252 cell = cell.findParent('td', false, true);
6255 if(!cell || typeof(cell) == 'undefined'){
6259 var row = cell.findParent('tr', false, true);
6261 if(!row || typeof(row) == 'undefined'){
6265 var cellIndex = cell.dom.cellIndex;
6266 var rowIndex = this.getRowIndex(row);
6268 if(this.cellSelection){
6269 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6272 if(this.rowSelection){
6273 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6277 sort : function(e,el)
6279 var col = Roo.get(el);
6281 if(!col.hasClass('sortable')){
6285 var sort = col.attr('sort');
6288 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6292 this.store.sortInfo = {field : sort, direction : dir};
6295 Roo.log("calling footer first");
6296 this.footer.onClick('first');
6299 this.store.load({ params : { start : 0 } });
6303 renderHeader : function()
6311 this.totalWidth = 0;
6313 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6315 var config = cm.config[i];
6320 html: cm.getColumnHeader(i)
6325 if(typeof(config.sortable) != 'undefined' && config.sortable){
6327 c.html = '<i class="glyphicon"></i>' + c.html;
6330 if(typeof(config.lgHeader) != 'undefined'){
6331 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6334 if(typeof(config.mdHeader) != 'undefined'){
6335 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6338 if(typeof(config.smHeader) != 'undefined'){
6339 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6342 if(typeof(config.xsHeader) != 'undefined'){
6343 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6350 if(typeof(config.tooltip) != 'undefined'){
6351 c.tooltip = config.tooltip;
6354 if(typeof(config.colspan) != 'undefined'){
6355 c.colspan = config.colspan;
6358 if(typeof(config.hidden) != 'undefined' && config.hidden){
6359 c.style += ' display:none;';
6362 if(typeof(config.dataIndex) != 'undefined'){
6363 c.sort = config.dataIndex;
6368 if(typeof(config.align) != 'undefined' && config.align.length){
6369 c.style += ' text-align:' + config.align + ';';
6372 if(typeof(config.width) != 'undefined'){
6373 c.style += ' width:' + config.width + 'px;';
6374 this.totalWidth += config.width;
6376 this.totalWidth += 100; // assume minimum of 100 per column?
6379 if(typeof(config.cls) != 'undefined'){
6380 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6383 ['xs','sm','md','lg'].map(function(size){
6385 if(typeof(config[size]) == 'undefined'){
6389 if (!config[size]) { // 0 = hidden
6390 c.cls += ' hidden-' + size;
6394 c.cls += ' col-' + size + '-' + config[size];
6404 renderBody : function()
6414 colspan : this.cm.getColumnCount()
6424 renderFooter : function()
6434 colspan : this.cm.getColumnCount()
6448 // Roo.log('ds onload');
6453 var ds = this.store;
6455 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6456 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6457 if (_this.store.sortInfo) {
6459 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6460 e.select('i', true).addClass(['glyphicon-arrow-up']);
6463 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6464 e.select('i', true).addClass(['glyphicon-arrow-down']);
6469 var tbody = this.mainBody;
6471 if(ds.getCount() > 0){
6472 ds.data.each(function(d,rowIndex){
6473 var row = this.renderRow(cm, ds, rowIndex);
6475 tbody.createChild(row);
6479 if(row.cellObjects.length){
6480 Roo.each(row.cellObjects, function(r){
6481 _this.renderCellObject(r);
6488 Roo.each(this.el.select('tbody td', true).elements, function(e){
6489 e.on('mouseover', _this.onMouseover, _this);
6492 Roo.each(this.el.select('tbody td', true).elements, function(e){
6493 e.on('mouseout', _this.onMouseout, _this);
6495 this.fireEvent('rowsrendered', this);
6496 //if(this.loadMask){
6497 // this.maskEl.hide();
6504 onUpdate : function(ds,record)
6506 this.refreshRow(record);
6510 onRemove : function(ds, record, index, isUpdate){
6511 if(isUpdate !== true){
6512 this.fireEvent("beforerowremoved", this, index, record);
6514 var bt = this.mainBody.dom;
6516 var rows = this.el.select('tbody > tr', true).elements;
6518 if(typeof(rows[index]) != 'undefined'){
6519 bt.removeChild(rows[index].dom);
6522 // if(bt.rows[index]){
6523 // bt.removeChild(bt.rows[index]);
6526 if(isUpdate !== true){
6527 //this.stripeRows(index);
6528 //this.syncRowHeights(index, index);
6530 this.fireEvent("rowremoved", this, index, record);
6534 onAdd : function(ds, records, rowIndex)
6536 //Roo.log('on Add called');
6537 // - note this does not handle multiple adding very well..
6538 var bt = this.mainBody.dom;
6539 for (var i =0 ; i < records.length;i++) {
6540 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6541 //Roo.log(records[i]);
6542 //Roo.log(this.store.getAt(rowIndex+i));
6543 this.insertRow(this.store, rowIndex + i, false);
6550 refreshRow : function(record){
6551 var ds = this.store, index;
6552 if(typeof record == 'number'){
6554 record = ds.getAt(index);
6556 index = ds.indexOf(record);
6558 this.insertRow(ds, index, true);
6560 this.onRemove(ds, record, index+1, true);
6562 //this.syncRowHeights(index, index);
6564 this.fireEvent("rowupdated", this, index, record);
6567 insertRow : function(dm, rowIndex, isUpdate){
6570 this.fireEvent("beforerowsinserted", this, rowIndex);
6572 //var s = this.getScrollState();
6573 var row = this.renderRow(this.cm, this.store, rowIndex);
6574 // insert before rowIndex..
6575 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6579 if(row.cellObjects.length){
6580 Roo.each(row.cellObjects, function(r){
6581 _this.renderCellObject(r);
6586 this.fireEvent("rowsinserted", this, rowIndex);
6587 //this.syncRowHeights(firstRow, lastRow);
6588 //this.stripeRows(firstRow);
6595 getRowDom : function(rowIndex)
6597 var rows = this.el.select('tbody > tr', true).elements;
6599 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6602 // returns the object tree for a tr..
6605 renderRow : function(cm, ds, rowIndex)
6608 var d = ds.getAt(rowIndex);
6615 var cellObjects = [];
6617 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6618 var config = cm.config[i];
6620 var renderer = cm.getRenderer(i);
6624 if(typeof(renderer) !== 'undefined'){
6625 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6627 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6628 // and are rendered into the cells after the row is rendered - using the id for the element.
6630 if(typeof(value) === 'object'){
6640 rowIndex : rowIndex,
6645 this.fireEvent('rowclass', this, rowcfg);
6649 cls : rowcfg.rowClass,
6651 html: (typeof(value) === 'object') ? '' : value
6658 if(typeof(config.colspan) != 'undefined'){
6659 td.colspan = config.colspan;
6662 if(typeof(config.hidden) != 'undefined' && config.hidden){
6663 td.style += ' display:none;';
6666 if(typeof(config.align) != 'undefined' && config.align.length){
6667 td.style += ' text-align:' + config.align + ';';
6670 if(typeof(config.width) != 'undefined'){
6671 td.style += ' width:' + config.width + 'px;';
6674 if(typeof(config.cursor) != 'undefined'){
6675 td.style += ' cursor:' + config.cursor + ';';
6678 if(typeof(config.cls) != 'undefined'){
6679 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6682 ['xs','sm','md','lg'].map(function(size){
6684 if(typeof(config[size]) == 'undefined'){
6688 if (!config[size]) { // 0 = hidden
6689 td.cls += ' hidden-' + size;
6693 td.cls += ' col-' + size + '-' + config[size];
6701 row.cellObjects = cellObjects;
6709 onBeforeLoad : function()
6711 //Roo.log('ds onBeforeLoad');
6715 //if(this.loadMask){
6716 // this.maskEl.show();
6724 this.el.select('tbody', true).first().dom.innerHTML = '';
6727 * Show or hide a row.
6728 * @param {Number} rowIndex to show or hide
6729 * @param {Boolean} state hide
6731 setRowVisibility : function(rowIndex, state)
6733 var bt = this.mainBody.dom;
6735 var rows = this.el.select('tbody > tr', true).elements;
6737 if(typeof(rows[rowIndex]) == 'undefined'){
6740 rows[rowIndex].dom.style.display = state ? '' : 'none';
6744 getSelectionModel : function(){
6746 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6748 return this.selModel;
6751 * Render the Roo.bootstrap object from renderder
6753 renderCellObject : function(r)
6757 var t = r.cfg.render(r.container);
6760 Roo.each(r.cfg.cn, function(c){
6762 container: t.getChildContainer(),
6765 _this.renderCellObject(child);
6770 getRowIndex : function(row)
6774 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6785 * Returns the grid's underlying element = used by panel.Grid
6786 * @return {Element} The element
6788 getGridEl : function(){
6792 * Forces a resize - used by panel.Grid
6793 * @return {Element} The element
6795 autoSize : function()
6797 //var ctr = Roo.get(this.container.dom.parentElement);
6798 var ctr = Roo.get(this.el.dom);
6800 var thd = this.getGridEl().select('thead',true).first();
6801 var tbd = this.getGridEl().select('tbody', true).first();
6802 var tfd = this.getGridEl().select('tfoot', true).first();
6804 var cw = ctr.getWidth();
6808 tbd.setSize(ctr.getWidth(),
6809 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6811 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6814 cw = Math.max(cw, this.totalWidth);
6815 this.getGridEl().select('tr',true).setWidth(cw);
6816 // resize 'expandable coloumn?
6818 return; // we doe not have a view in this design..
6821 onBodyScroll: function()
6823 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6824 this.mainHead.setStyle({
6825 'position' : 'relative',
6826 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6831 var scrollHeight = this.mainBody.dom.scrollHeight;
6833 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6835 var height = this.mainBody.getHeight();
6837 if(scrollHeight - height == scrollTop) {
6839 var total = this.ds.getTotalCount();
6841 if(this.footer.cursor + this.footer.pageSize < total){
6843 this.footer.ds.load({
6845 start : this.footer.cursor + this.footer.pageSize,
6846 limit : this.footer.pageSize
6867 * @class Roo.bootstrap.TableCell
6868 * @extends Roo.bootstrap.Component
6869 * Bootstrap TableCell class
6870 * @cfg {String} html cell contain text
6871 * @cfg {String} cls cell class
6872 * @cfg {String} tag cell tag (td|th) default td
6873 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6874 * @cfg {String} align Aligns the content in a cell
6875 * @cfg {String} axis Categorizes cells
6876 * @cfg {String} bgcolor Specifies the background color of a cell
6877 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6878 * @cfg {Number} colspan Specifies the number of columns a cell should span
6879 * @cfg {String} headers Specifies one or more header cells a cell is related to
6880 * @cfg {Number} height Sets the height of a cell
6881 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6882 * @cfg {Number} rowspan Sets the number of rows a cell should span
6883 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6884 * @cfg {String} valign Vertical aligns the content in a cell
6885 * @cfg {Number} width Specifies the width of a cell
6888 * Create a new TableCell
6889 * @param {Object} config The config object
6892 Roo.bootstrap.TableCell = function(config){
6893 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6896 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6916 getAutoCreate : function(){
6917 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6937 cfg.align=this.align
6943 cfg.bgcolor=this.bgcolor
6946 cfg.charoff=this.charoff
6949 cfg.colspan=this.colspan
6952 cfg.headers=this.headers
6955 cfg.height=this.height
6958 cfg.nowrap=this.nowrap
6961 cfg.rowspan=this.rowspan
6964 cfg.scope=this.scope
6967 cfg.valign=this.valign
6970 cfg.width=this.width
6989 * @class Roo.bootstrap.TableRow
6990 * @extends Roo.bootstrap.Component
6991 * Bootstrap TableRow class
6992 * @cfg {String} cls row class
6993 * @cfg {String} align Aligns the content in a table row
6994 * @cfg {String} bgcolor Specifies a background color for a table row
6995 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6996 * @cfg {String} valign Vertical aligns the content in a table row
6999 * Create a new TableRow
7000 * @param {Object} config The config object
7003 Roo.bootstrap.TableRow = function(config){
7004 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7007 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7015 getAutoCreate : function(){
7016 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7026 cfg.align = this.align;
7029 cfg.bgcolor = this.bgcolor;
7032 cfg.charoff = this.charoff;
7035 cfg.valign = this.valign;
7053 * @class Roo.bootstrap.TableBody
7054 * @extends Roo.bootstrap.Component
7055 * Bootstrap TableBody class
7056 * @cfg {String} cls element class
7057 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7058 * @cfg {String} align Aligns the content inside the element
7059 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7060 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7063 * Create a new TableBody
7064 * @param {Object} config The config object
7067 Roo.bootstrap.TableBody = function(config){
7068 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7071 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7079 getAutoCreate : function(){
7080 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7094 cfg.align = this.align;
7097 cfg.charoff = this.charoff;
7100 cfg.valign = this.valign;
7107 // initEvents : function()
7114 // this.store = Roo.factory(this.store, Roo.data);
7115 // this.store.on('load', this.onLoad, this);
7117 // this.store.load();
7121 // onLoad: function ()
7123 // this.fireEvent('load', this);
7133 * Ext JS Library 1.1.1
7134 * Copyright(c) 2006-2007, Ext JS, LLC.
7136 * Originally Released Under LGPL - original licence link has changed is not relivant.
7139 * <script type="text/javascript">
7142 // as we use this in bootstrap.
7143 Roo.namespace('Roo.form');
7145 * @class Roo.form.Action
7146 * Internal Class used to handle form actions
7148 * @param {Roo.form.BasicForm} el The form element or its id
7149 * @param {Object} config Configuration options
7154 // define the action interface
7155 Roo.form.Action = function(form, options){
7157 this.options = options || {};
7160 * Client Validation Failed
7163 Roo.form.Action.CLIENT_INVALID = 'client';
7165 * Server Validation Failed
7168 Roo.form.Action.SERVER_INVALID = 'server';
7170 * Connect to Server Failed
7173 Roo.form.Action.CONNECT_FAILURE = 'connect';
7175 * Reading Data from Server Failed
7178 Roo.form.Action.LOAD_FAILURE = 'load';
7180 Roo.form.Action.prototype = {
7182 failureType : undefined,
7183 response : undefined,
7187 run : function(options){
7192 success : function(response){
7197 handleResponse : function(response){
7201 // default connection failure
7202 failure : function(response){
7204 this.response = response;
7205 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7206 this.form.afterAction(this, false);
7209 processResponse : function(response){
7210 this.response = response;
7211 if(!response.responseText){
7214 this.result = this.handleResponse(response);
7218 // utility functions used internally
7219 getUrl : function(appendParams){
7220 var url = this.options.url || this.form.url || this.form.el.dom.action;
7222 var p = this.getParams();
7224 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7230 getMethod : function(){
7231 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7234 getParams : function(){
7235 var bp = this.form.baseParams;
7236 var p = this.options.params;
7238 if(typeof p == "object"){
7239 p = Roo.urlEncode(Roo.applyIf(p, bp));
7240 }else if(typeof p == 'string' && bp){
7241 p += '&' + Roo.urlEncode(bp);
7244 p = Roo.urlEncode(bp);
7249 createCallback : function(){
7251 success: this.success,
7252 failure: this.failure,
7254 timeout: (this.form.timeout*1000),
7255 upload: this.form.fileUpload ? this.success : undefined
7260 Roo.form.Action.Submit = function(form, options){
7261 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7264 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7267 haveProgress : false,
7268 uploadComplete : false,
7270 // uploadProgress indicator.
7271 uploadProgress : function()
7273 if (!this.form.progressUrl) {
7277 if (!this.haveProgress) {
7278 Roo.MessageBox.progress("Uploading", "Uploading");
7280 if (this.uploadComplete) {
7281 Roo.MessageBox.hide();
7285 this.haveProgress = true;
7287 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7289 var c = new Roo.data.Connection();
7291 url : this.form.progressUrl,
7296 success : function(req){
7297 //console.log(data);
7301 rdata = Roo.decode(req.responseText)
7303 Roo.log("Invalid data from server..");
7307 if (!rdata || !rdata.success) {
7309 Roo.MessageBox.alert(Roo.encode(rdata));
7312 var data = rdata.data;
7314 if (this.uploadComplete) {
7315 Roo.MessageBox.hide();
7320 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7321 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7324 this.uploadProgress.defer(2000,this);
7327 failure: function(data) {
7328 Roo.log('progress url failed ');
7339 // run get Values on the form, so it syncs any secondary forms.
7340 this.form.getValues();
7342 var o = this.options;
7343 var method = this.getMethod();
7344 var isPost = method == 'POST';
7345 if(o.clientValidation === false || this.form.isValid()){
7347 if (this.form.progressUrl) {
7348 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7349 (new Date() * 1) + '' + Math.random());
7354 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7355 form:this.form.el.dom,
7356 url:this.getUrl(!isPost),
7358 params:isPost ? this.getParams() : null,
7359 isUpload: this.form.fileUpload
7362 this.uploadProgress();
7364 }else if (o.clientValidation !== false){ // client validation failed
7365 this.failureType = Roo.form.Action.CLIENT_INVALID;
7366 this.form.afterAction(this, false);
7370 success : function(response)
7372 this.uploadComplete= true;
7373 if (this.haveProgress) {
7374 Roo.MessageBox.hide();
7378 var result = this.processResponse(response);
7379 if(result === true || result.success){
7380 this.form.afterAction(this, true);
7384 this.form.markInvalid(result.errors);
7385 this.failureType = Roo.form.Action.SERVER_INVALID;
7387 this.form.afterAction(this, false);
7389 failure : function(response)
7391 this.uploadComplete= true;
7392 if (this.haveProgress) {
7393 Roo.MessageBox.hide();
7396 this.response = response;
7397 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7398 this.form.afterAction(this, false);
7401 handleResponse : function(response){
7402 if(this.form.errorReader){
7403 var rs = this.form.errorReader.read(response);
7406 for(var i = 0, len = rs.records.length; i < len; i++) {
7407 var r = rs.records[i];
7411 if(errors.length < 1){
7415 success : rs.success,
7421 ret = Roo.decode(response.responseText);
7425 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7435 Roo.form.Action.Load = function(form, options){
7436 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7437 this.reader = this.form.reader;
7440 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7445 Roo.Ajax.request(Roo.apply(
7446 this.createCallback(), {
7447 method:this.getMethod(),
7448 url:this.getUrl(false),
7449 params:this.getParams()
7453 success : function(response){
7455 var result = this.processResponse(response);
7456 if(result === true || !result.success || !result.data){
7457 this.failureType = Roo.form.Action.LOAD_FAILURE;
7458 this.form.afterAction(this, false);
7461 this.form.clearInvalid();
7462 this.form.setValues(result.data);
7463 this.form.afterAction(this, true);
7466 handleResponse : function(response){
7467 if(this.form.reader){
7468 var rs = this.form.reader.read(response);
7469 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7471 success : rs.success,
7475 return Roo.decode(response.responseText);
7479 Roo.form.Action.ACTION_TYPES = {
7480 'load' : Roo.form.Action.Load,
7481 'submit' : Roo.form.Action.Submit
7490 * @class Roo.bootstrap.Form
7491 * @extends Roo.bootstrap.Component
7492 * Bootstrap Form class
7493 * @cfg {String} method GET | POST (default POST)
7494 * @cfg {String} labelAlign top | left (default top)
7495 * @cfg {String} align left | right - for navbars
7496 * @cfg {Boolean} loadMask load mask when submit (default true)
7501 * @param {Object} config The config object
7505 Roo.bootstrap.Form = function(config){
7506 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7508 Roo.bootstrap.Form.popover.apply();
7512 * @event clientvalidation
7513 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7514 * @param {Form} this
7515 * @param {Boolean} valid true if the form has passed client-side validation
7517 clientvalidation: true,
7519 * @event beforeaction
7520 * Fires before any action is performed. Return false to cancel the action.
7521 * @param {Form} this
7522 * @param {Action} action The action to be performed
7526 * @event actionfailed
7527 * Fires when an action fails.
7528 * @param {Form} this
7529 * @param {Action} action The action that failed
7531 actionfailed : true,
7533 * @event actioncomplete
7534 * Fires when an action is completed.
7535 * @param {Form} this
7536 * @param {Action} action The action that completed
7538 actioncomplete : true
7543 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7546 * @cfg {String} method
7547 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7552 * The URL to use for form actions if one isn't supplied in the action options.
7555 * @cfg {Boolean} fileUpload
7556 * Set to true if this form is a file upload.
7560 * @cfg {Object} baseParams
7561 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7565 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7569 * @cfg {Sting} align (left|right) for navbar forms
7574 activeAction : null,
7577 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7578 * element by passing it or its id or mask the form itself by passing in true.
7581 waitMsgTarget : false,
7586 * @cfg {Boolean} errorMask (true|false) default false
7591 * @cfg {Number} maskOffset Default 100
7595 getAutoCreate : function(){
7599 method : this.method || 'POST',
7600 id : this.id || Roo.id(),
7603 if (this.parent().xtype.match(/^Nav/)) {
7604 cfg.cls = 'navbar-form navbar-' + this.align;
7608 if (this.labelAlign == 'left' ) {
7609 cfg.cls += ' form-horizontal';
7615 initEvents : function()
7617 this.el.on('submit', this.onSubmit, this);
7618 // this was added as random key presses on the form where triggering form submit.
7619 this.el.on('keypress', function(e) {
7620 if (e.getCharCode() != 13) {
7623 // we might need to allow it for textareas.. and some other items.
7624 // check e.getTarget().
7626 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7630 Roo.log("keypress blocked");
7638 onSubmit : function(e){
7643 * Returns true if client-side validation on the form is successful.
7646 isValid : function(){
7647 var items = this.getItems();
7651 items.each(function(f){
7658 if(!target && f.el.isVisible(true)){
7664 if(this.errorMask && !valid){
7665 Roo.bootstrap.Form.popover.mask(this, target);
7672 * Returns true if any fields in this form have changed since their original load.
7675 isDirty : function(){
7677 var items = this.getItems();
7678 items.each(function(f){
7688 * Performs a predefined action (submit or load) or custom actions you define on this form.
7689 * @param {String} actionName The name of the action type
7690 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7691 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7692 * accept other config options):
7694 Property Type Description
7695 ---------------- --------------- ----------------------------------------------------------------------------------
7696 url String The url for the action (defaults to the form's url)
7697 method String The form method to use (defaults to the form's method, or POST if not defined)
7698 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7699 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7700 validate the form on the client (defaults to false)
7702 * @return {BasicForm} this
7704 doAction : function(action, options){
7705 if(typeof action == 'string'){
7706 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7708 if(this.fireEvent('beforeaction', this, action) !== false){
7709 this.beforeAction(action);
7710 action.run.defer(100, action);
7716 beforeAction : function(action){
7717 var o = action.options;
7720 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7722 // not really supported yet.. ??
7724 //if(this.waitMsgTarget === true){
7725 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7726 //}else if(this.waitMsgTarget){
7727 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7728 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7730 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7736 afterAction : function(action, success){
7737 this.activeAction = null;
7738 var o = action.options;
7740 //if(this.waitMsgTarget === true){
7742 //}else if(this.waitMsgTarget){
7743 // this.waitMsgTarget.unmask();
7745 // Roo.MessageBox.updateProgress(1);
7746 // Roo.MessageBox.hide();
7753 Roo.callback(o.success, o.scope, [this, action]);
7754 this.fireEvent('actioncomplete', this, action);
7758 // failure condition..
7759 // we have a scenario where updates need confirming.
7760 // eg. if a locking scenario exists..
7761 // we look for { errors : { needs_confirm : true }} in the response.
7763 (typeof(action.result) != 'undefined') &&
7764 (typeof(action.result.errors) != 'undefined') &&
7765 (typeof(action.result.errors.needs_confirm) != 'undefined')
7768 Roo.log("not supported yet");
7771 Roo.MessageBox.confirm(
7772 "Change requires confirmation",
7773 action.result.errorMsg,
7778 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7788 Roo.callback(o.failure, o.scope, [this, action]);
7789 // show an error message if no failed handler is set..
7790 if (!this.hasListener('actionfailed')) {
7791 Roo.log("need to add dialog support");
7793 Roo.MessageBox.alert("Error",
7794 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7795 action.result.errorMsg :
7796 "Saving Failed, please check your entries or try again"
7801 this.fireEvent('actionfailed', this, action);
7806 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7807 * @param {String} id The value to search for
7810 findField : function(id){
7811 var items = this.getItems();
7812 var field = items.get(id);
7814 items.each(function(f){
7815 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7822 return field || null;
7825 * Mark fields in this form invalid in bulk.
7826 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7827 * @return {BasicForm} this
7829 markInvalid : function(errors){
7830 if(errors instanceof Array){
7831 for(var i = 0, len = errors.length; i < len; i++){
7832 var fieldError = errors[i];
7833 var f = this.findField(fieldError.id);
7835 f.markInvalid(fieldError.msg);
7841 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7842 field.markInvalid(errors[id]);
7846 //Roo.each(this.childForms || [], function (f) {
7847 // f.markInvalid(errors);
7854 * Set values for fields in this form in bulk.
7855 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7856 * @return {BasicForm} this
7858 setValues : function(values){
7859 if(values instanceof Array){ // array of objects
7860 for(var i = 0, len = values.length; i < len; i++){
7862 var f = this.findField(v.id);
7864 f.setValue(v.value);
7865 if(this.trackResetOnLoad){
7866 f.originalValue = f.getValue();
7870 }else{ // object hash
7873 if(typeof values[id] != 'function' && (field = this.findField(id))){
7875 if (field.setFromData &&
7877 field.displayField &&
7878 // combos' with local stores can
7879 // be queried via setValue()
7880 // to set their value..
7881 (field.store && !field.store.isLocal)
7885 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7886 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7887 field.setFromData(sd);
7890 field.setValue(values[id]);
7894 if(this.trackResetOnLoad){
7895 field.originalValue = field.getValue();
7901 //Roo.each(this.childForms || [], function (f) {
7902 // f.setValues(values);
7909 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7910 * they are returned as an array.
7911 * @param {Boolean} asString
7914 getValues : function(asString){
7915 //if (this.childForms) {
7916 // copy values from the child forms
7917 // Roo.each(this.childForms, function (f) {
7918 // this.setValues(f.getValues());
7924 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7925 if(asString === true){
7928 return Roo.urlDecode(fs);
7932 * Returns the fields in this form as an object with key/value pairs.
7933 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7936 getFieldValues : function(with_hidden)
7938 var items = this.getItems();
7940 items.each(function(f){
7944 var v = f.getValue();
7945 if (f.inputType =='radio') {
7946 if (typeof(ret[f.getName()]) == 'undefined') {
7947 ret[f.getName()] = ''; // empty..
7950 if (!f.el.dom.checked) {
7958 // not sure if this supported any more..
7959 if ((typeof(v) == 'object') && f.getRawValue) {
7960 v = f.getRawValue() ; // dates..
7962 // combo boxes where name != hiddenName...
7963 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7964 ret[f.name] = f.getRawValue();
7966 ret[f.getName()] = v;
7973 * Clears all invalid messages in this form.
7974 * @return {BasicForm} this
7976 clearInvalid : function(){
7977 var items = this.getItems();
7979 items.each(function(f){
7990 * @return {BasicForm} this
7993 var items = this.getItems();
7994 items.each(function(f){
7998 Roo.each(this.childForms || [], function (f) {
8005 getItems : function()
8007 var r=new Roo.util.MixedCollection(false, function(o){
8008 return o.id || (o.id = Roo.id());
8010 var iter = function(el) {
8017 Roo.each(el.items,function(e) {
8034 Roo.apply(Roo.bootstrap.Form, {
8061 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8062 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8063 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8064 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8067 this.maskEl.top.enableDisplayMode("block");
8068 this.maskEl.left.enableDisplayMode("block");
8069 this.maskEl.bottom.enableDisplayMode("block");
8070 this.maskEl.right.enableDisplayMode("block");
8072 this.toolTip = new Roo.bootstrap.Tooltip({
8073 cls : 'roo-form-error-popover',
8075 'left' : ['r-l', [-2,0], 'right'],
8076 'right' : ['l-r', [2,0], 'left'],
8077 'bottom' : ['tl-bl', [0,2], 'top'],
8078 'top' : [ 'bl-tl', [0,-2], 'bottom']
8082 this.toolTip.render(Roo.get(document.body));
8084 this.toolTip.el.enableDisplayMode("block");
8086 Roo.get(document.body).on('click', function(){
8090 Roo.get(document.body).on('touchstart', function(){
8094 this.isApplied = true
8097 mask : function(form, target)
8101 this.target = target;
8103 if(!this.form.errorMask || !target.el){
8107 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8109 var ot = this.target.el.calcOffsetsTo(scrollable);
8111 var scrollTo = ot[1] - this.form.maskOffset;
8113 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8115 scrollable.scrollTo('top', scrollTo);
8117 var box = this.target.el.getBox();
8119 var zIndex = Roo.bootstrap.Modal.zIndex++;
8121 this.maskEl.top.setStyle('position', 'fixed');
8122 this.maskEl.top.setStyle('z-index', zIndex);
8123 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8124 this.maskEl.top.setXY([0, 0]);
8125 this.maskEl.top.show();
8127 this.maskEl.left.setStyle('position', 'fixed');
8128 this.maskEl.left.setStyle('z-index', zIndex);
8129 this.maskEl.left.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8130 this.maskEl.left.setXY([box.right + this.padding, box.y - this.padding]);
8131 this.maskEl.left.show();
8133 this.maskEl.bottom.setStyle('position', 'fixed');
8134 this.maskEl.bottom.setStyle('z-index', zIndex);
8135 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8136 this.maskEl.bottom.setXY([0, box.bottom + this.padding]);
8137 this.maskEl.bottom.show();
8139 this.maskEl.right.setStyle('position', 'fixed');
8140 this.maskEl.right.setStyle('z-index', zIndex);
8141 this.maskEl.right.setSize(box.x - this.padding, box.height + this.padding * 2);
8142 this.maskEl.right.setXY([0, box.y - this.padding]);
8143 this.maskEl.right.show();
8146 this.toolTip.bindEl = this.target.el;
8148 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8150 var tip = this.target.blankText;
8152 if(this.target.getValue() !== '' && this.target.regexText.length){
8153 tip = this.target.regexText;
8156 this.toolTip.show(tip);
8158 this.intervalID = window.setInterval(function() {
8159 Roo.bootstrap.Form.popover.unmask();
8162 window.onwheel = function(){ return false;};
8164 (function(){ this.isMasked = true; }).defer(500, this);
8172 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8176 this.maskEl.top.setStyle('position', 'absolute');
8177 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8178 this.maskEl.top.hide();
8180 this.maskEl.left.setStyle('position', 'absolute');
8181 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8182 this.maskEl.left.hide();
8184 this.maskEl.bottom.setStyle('position', 'absolute');
8185 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8186 this.maskEl.bottom.hide();
8188 this.maskEl.right.setStyle('position', 'absolute');
8189 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8190 this.maskEl.right.hide();
8192 this.toolTip.hide();
8194 this.toolTip.el.hide();
8196 window.onwheel = function(){ return true;};
8198 if(this.intervalID){
8199 window.clearInterval(this.intervalID);
8200 this.intervalID = false;
8203 this.isMasked = false;
8213 * Ext JS Library 1.1.1
8214 * Copyright(c) 2006-2007, Ext JS, LLC.
8216 * Originally Released Under LGPL - original licence link has changed is not relivant.
8219 * <script type="text/javascript">
8222 * @class Roo.form.VTypes
8223 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8226 Roo.form.VTypes = function(){
8227 // closure these in so they are only created once.
8228 var alpha = /^[a-zA-Z_]+$/;
8229 var alphanum = /^[a-zA-Z0-9_]+$/;
8230 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8231 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8233 // All these messages and functions are configurable
8236 * The function used to validate email addresses
8237 * @param {String} value The email address
8239 'email' : function(v){
8240 return email.test(v);
8243 * The error text to display when the email validation function returns false
8246 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8248 * The keystroke filter mask to be applied on email input
8251 'emailMask' : /[a-z0-9_\.\-@]/i,
8254 * The function used to validate URLs
8255 * @param {String} value The URL
8257 'url' : function(v){
8261 * The error text to display when the url validation function returns false
8264 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8267 * The function used to validate alpha values
8268 * @param {String} value The value
8270 'alpha' : function(v){
8271 return alpha.test(v);
8274 * The error text to display when the alpha validation function returns false
8277 'alphaText' : 'This field should only contain letters and _',
8279 * The keystroke filter mask to be applied on alpha input
8282 'alphaMask' : /[a-z_]/i,
8285 * The function used to validate alphanumeric values
8286 * @param {String} value The value
8288 'alphanum' : function(v){
8289 return alphanum.test(v);
8292 * The error text to display when the alphanumeric validation function returns false
8295 'alphanumText' : 'This field should only contain letters, numbers and _',
8297 * The keystroke filter mask to be applied on alphanumeric input
8300 'alphanumMask' : /[a-z0-9_]/i
8310 * @class Roo.bootstrap.Input
8311 * @extends Roo.bootstrap.Component
8312 * Bootstrap Input class
8313 * @cfg {Boolean} disabled is it disabled
8314 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8315 * @cfg {String} name name of the input
8316 * @cfg {string} fieldLabel - the label associated
8317 * @cfg {string} placeholder - placeholder to put in text.
8318 * @cfg {string} before - input group add on before
8319 * @cfg {string} after - input group add on after
8320 * @cfg {string} size - (lg|sm) or leave empty..
8321 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8322 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8323 * @cfg {Number} md colspan out of 12 for computer-sized screens
8324 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8325 * @cfg {string} value default value of the input
8326 * @cfg {Number} labelWidth set the width of label
8327 * @cfg {Number} labellg set the width of label (1-12)
8328 * @cfg {Number} labelmd set the width of label (1-12)
8329 * @cfg {Number} labelsm set the width of label (1-12)
8330 * @cfg {Number} labelxs set the width of label (1-12)
8331 * @cfg {String} labelAlign (top|left)
8332 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8333 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8334 * @cfg {String} indicatorpos (left|right) default left
8336 * @cfg {String} align (left|center|right) Default left
8337 * @cfg {Boolean} forceFeedback (true|false) Default false
8343 * Create a new Input
8344 * @param {Object} config The config object
8347 Roo.bootstrap.Input = function(config){
8349 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8354 * Fires when this field receives input focus.
8355 * @param {Roo.form.Field} this
8360 * Fires when this field loses input focus.
8361 * @param {Roo.form.Field} this
8366 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8367 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8368 * @param {Roo.form.Field} this
8369 * @param {Roo.EventObject} e The event object
8374 * Fires just before the field blurs if the field value has changed.
8375 * @param {Roo.form.Field} this
8376 * @param {Mixed} newValue The new value
8377 * @param {Mixed} oldValue The original value
8382 * Fires after the field has been marked as invalid.
8383 * @param {Roo.form.Field} this
8384 * @param {String} msg The validation message
8389 * Fires after the field has been validated with no errors.
8390 * @param {Roo.form.Field} this
8395 * Fires after the key up
8396 * @param {Roo.form.Field} this
8397 * @param {Roo.EventObject} e The event Object
8403 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8405 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8406 automatic validation (defaults to "keyup").
8408 validationEvent : "keyup",
8410 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8412 validateOnBlur : true,
8414 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8416 validationDelay : 250,
8418 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8420 focusClass : "x-form-focus", // not needed???
8424 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8426 invalidClass : "has-warning",
8429 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8431 validClass : "has-success",
8434 * @cfg {Boolean} hasFeedback (true|false) default true
8439 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8441 invalidFeedbackClass : "glyphicon-warning-sign",
8444 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8446 validFeedbackClass : "glyphicon-ok",
8449 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8451 selectOnFocus : false,
8454 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8458 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8463 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8465 disableKeyFilter : false,
8468 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8472 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8476 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8478 blankText : "Please complete this mandatory field",
8481 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8485 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8487 maxLength : Number.MAX_VALUE,
8489 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8491 minLengthText : "The minimum length for this field is {0}",
8493 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8495 maxLengthText : "The maximum length for this field is {0}",
8499 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8500 * If available, this function will be called only after the basic validators all return true, and will be passed the
8501 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8505 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8506 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8507 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8511 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8515 autocomplete: false,
8534 formatedValue : false,
8535 forceFeedback : false,
8537 indicatorpos : 'left',
8544 parentLabelAlign : function()
8547 while (parent.parent()) {
8548 parent = parent.parent();
8549 if (typeof(parent.labelAlign) !='undefined') {
8550 return parent.labelAlign;
8557 getAutoCreate : function()
8559 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8565 if(this.inputType != 'hidden'){
8566 cfg.cls = 'form-group' //input-group
8572 type : this.inputType,
8574 cls : 'form-control',
8575 placeholder : this.placeholder || '',
8576 autocomplete : this.autocomplete || 'new-password'
8580 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8583 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8584 input.maxLength = this.maxLength;
8587 if (this.disabled) {
8588 input.disabled=true;
8591 if (this.readOnly) {
8592 input.readonly=true;
8596 input.name = this.name;
8600 input.cls += ' input-' + this.size;
8604 ['xs','sm','md','lg'].map(function(size){
8605 if (settings[size]) {
8606 cfg.cls += ' col-' + size + '-' + settings[size];
8610 var inputblock = input;
8614 cls: 'glyphicon form-control-feedback'
8617 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8620 cls : 'has-feedback',
8628 if (this.before || this.after) {
8631 cls : 'input-group',
8635 if (this.before && typeof(this.before) == 'string') {
8637 inputblock.cn.push({
8639 cls : 'roo-input-before input-group-addon',
8643 if (this.before && typeof(this.before) == 'object') {
8644 this.before = Roo.factory(this.before);
8646 inputblock.cn.push({
8648 cls : 'roo-input-before input-group-' +
8649 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8653 inputblock.cn.push(input);
8655 if (this.after && typeof(this.after) == 'string') {
8656 inputblock.cn.push({
8658 cls : 'roo-input-after input-group-addon',
8662 if (this.after && typeof(this.after) == 'object') {
8663 this.after = Roo.factory(this.after);
8665 inputblock.cn.push({
8667 cls : 'roo-input-after input-group-' +
8668 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8672 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8673 inputblock.cls += ' has-feedback';
8674 inputblock.cn.push(feedback);
8678 if (align ==='left' && this.fieldLabel.length) {
8680 cfg.cls += ' roo-form-group-label-left';
8685 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8686 tooltip : 'This field is required'
8691 cls : 'control-label',
8692 html : this.fieldLabel
8703 var labelCfg = cfg.cn[1];
8704 var contentCfg = cfg.cn[2];
8706 if(this.indicatorpos == 'right'){
8711 cls : 'control-label',
8712 html : this.fieldLabel
8717 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8718 tooltip : 'This field is required'
8729 labelCfg = cfg.cn[0];
8730 contentCfg = cfg.cn[2];
8734 if(this.labelWidth > 12){
8735 labelCfg.style = "width: " + this.labelWidth + 'px';
8738 if(this.labelWidth < 13 && this.labelmd == 0){
8739 this.labelmd = this.labelWidth;
8742 if(this.labellg > 0){
8743 labelCfg.cls += ' col-lg-' + this.labellg;
8744 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8747 if(this.labelmd > 0){
8748 labelCfg.cls += ' col-md-' + this.labelmd;
8749 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8752 if(this.labelsm > 0){
8753 labelCfg.cls += ' col-sm-' + this.labelsm;
8754 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8757 if(this.labelxs > 0){
8758 labelCfg.cls += ' col-xs-' + this.labelxs;
8759 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8763 } else if ( this.fieldLabel.length) {
8768 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8769 tooltip : 'This field is required'
8773 //cls : 'input-group-addon',
8774 html : this.fieldLabel
8782 if(this.indicatorpos == 'right'){
8787 //cls : 'input-group-addon',
8788 html : this.fieldLabel
8793 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8794 tooltip : 'This field is required'
8814 if (this.parentType === 'Navbar' && this.parent().bar) {
8815 cfg.cls += ' navbar-form';
8818 if (this.parentType === 'NavGroup') {
8819 cfg.cls += ' navbar-form';
8827 * return the real input element.
8829 inputEl: function ()
8831 return this.el.select('input.form-control',true).first();
8834 tooltipEl : function()
8836 return this.inputEl();
8839 indicatorEl : function()
8841 var indicator = this.el.select('i.roo-required-indicator',true).first();
8851 setDisabled : function(v)
8853 var i = this.inputEl().dom;
8855 i.removeAttribute('disabled');
8859 i.setAttribute('disabled','true');
8861 initEvents : function()
8864 this.inputEl().on("keydown" , this.fireKey, this);
8865 this.inputEl().on("focus", this.onFocus, this);
8866 this.inputEl().on("blur", this.onBlur, this);
8868 this.inputEl().relayEvent('keyup', this);
8870 this.indicator = this.indicatorEl();
8873 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8874 this.indicator.hide();
8877 // reference to original value for reset
8878 this.originalValue = this.getValue();
8879 //Roo.form.TextField.superclass.initEvents.call(this);
8880 if(this.validationEvent == 'keyup'){
8881 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8882 this.inputEl().on('keyup', this.filterValidation, this);
8884 else if(this.validationEvent !== false){
8885 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8888 if(this.selectOnFocus){
8889 this.on("focus", this.preFocus, this);
8892 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8893 this.inputEl().on("keypress", this.filterKeys, this);
8895 this.inputEl().relayEvent('keypress', this);
8898 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8899 this.el.on("click", this.autoSize, this);
8902 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8903 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8906 if (typeof(this.before) == 'object') {
8907 this.before.render(this.el.select('.roo-input-before',true).first());
8909 if (typeof(this.after) == 'object') {
8910 this.after.render(this.el.select('.roo-input-after',true).first());
8915 filterValidation : function(e){
8916 if(!e.isNavKeyPress()){
8917 this.validationTask.delay(this.validationDelay);
8921 * Validates the field value
8922 * @return {Boolean} True if the value is valid, else false
8924 validate : function(){
8925 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8926 if(this.disabled || this.validateValue(this.getRawValue())){
8937 * Validates a value according to the field's validation rules and marks the field as invalid
8938 * if the validation fails
8939 * @param {Mixed} value The value to validate
8940 * @return {Boolean} True if the value is valid, else false
8942 validateValue : function(value){
8943 if(value.length < 1) { // if it's blank
8944 if(this.allowBlank){
8947 return this.inputEl().hasClass('hide') ? true : false;
8950 if(value.length < this.minLength){
8953 if(value.length > this.maxLength){
8957 var vt = Roo.form.VTypes;
8958 if(!vt[this.vtype](value, this)){
8962 if(typeof this.validator == "function"){
8963 var msg = this.validator(value);
8969 if(this.regex && !this.regex.test(value)){
8979 fireKey : function(e){
8980 //Roo.log('field ' + e.getKey());
8981 if(e.isNavKeyPress()){
8982 this.fireEvent("specialkey", this, e);
8985 focus : function (selectText){
8987 this.inputEl().focus();
8988 if(selectText === true){
8989 this.inputEl().dom.select();
8995 onFocus : function(){
8996 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8997 // this.el.addClass(this.focusClass);
9000 this.hasFocus = true;
9001 this.startValue = this.getValue();
9002 this.fireEvent("focus", this);
9006 beforeBlur : Roo.emptyFn,
9010 onBlur : function(){
9012 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9013 //this.el.removeClass(this.focusClass);
9015 this.hasFocus = false;
9016 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9019 var v = this.getValue();
9020 if(String(v) !== String(this.startValue)){
9021 this.fireEvent('change', this, v, this.startValue);
9023 this.fireEvent("blur", this);
9027 * Resets the current field value to the originally loaded value and clears any validation messages
9030 this.setValue(this.originalValue);
9034 * Returns the name of the field
9035 * @return {Mixed} name The name field
9037 getName: function(){
9041 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9042 * @return {Mixed} value The field value
9044 getValue : function(){
9046 var v = this.inputEl().getValue();
9051 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9052 * @return {Mixed} value The field value
9054 getRawValue : function(){
9055 var v = this.inputEl().getValue();
9061 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9062 * @param {Mixed} value The value to set
9064 setRawValue : function(v){
9065 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9068 selectText : function(start, end){
9069 var v = this.getRawValue();
9071 start = start === undefined ? 0 : start;
9072 end = end === undefined ? v.length : end;
9073 var d = this.inputEl().dom;
9074 if(d.setSelectionRange){
9075 d.setSelectionRange(start, end);
9076 }else if(d.createTextRange){
9077 var range = d.createTextRange();
9078 range.moveStart("character", start);
9079 range.moveEnd("character", v.length-end);
9086 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9087 * @param {Mixed} value The value to set
9089 setValue : function(v){
9092 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9098 processValue : function(value){
9099 if(this.stripCharsRe){
9100 var newValue = value.replace(this.stripCharsRe, '');
9101 if(newValue !== value){
9102 this.setRawValue(newValue);
9109 preFocus : function(){
9111 if(this.selectOnFocus){
9112 this.inputEl().dom.select();
9115 filterKeys : function(e){
9117 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9120 var c = e.getCharCode(), cc = String.fromCharCode(c);
9121 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9124 if(!this.maskRe.test(cc)){
9129 * Clear any invalid styles/messages for this field
9131 clearInvalid : function(){
9133 if(!this.el || this.preventMark){ // not rendered
9138 this.el.removeClass(this.invalidClass);
9140 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9142 var feedback = this.el.select('.form-control-feedback', true).first();
9145 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9150 this.fireEvent('valid', this);
9154 * Mark this field as valid
9156 markValid : function()
9158 if(!this.el || this.preventMark){ // not rendered...
9162 this.el.removeClass([this.invalidClass, this.validClass]);
9164 var feedback = this.el.select('.form-control-feedback', true).first();
9167 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9174 if(this.allowBlank && !this.getRawValue().length){
9179 this.indicator.hide();
9182 this.el.addClass(this.validClass);
9184 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9186 var feedback = this.el.select('.form-control-feedback', true).first();
9189 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9190 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9195 this.fireEvent('valid', this);
9199 * Mark this field as invalid
9200 * @param {String} msg The validation message
9202 markInvalid : function(msg)
9204 if(!this.el || this.preventMark){ // not rendered
9208 this.el.removeClass([this.invalidClass, this.validClass]);
9210 var feedback = this.el.select('.form-control-feedback', true).first();
9213 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9220 if(this.allowBlank && !this.getRawValue().length){
9225 this.indicator.show();
9228 this.el.addClass(this.invalidClass);
9230 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9232 var feedback = this.el.select('.form-control-feedback', true).first();
9235 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9237 if(this.getValue().length || this.forceFeedback){
9238 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9245 this.fireEvent('invalid', this, msg);
9248 SafariOnKeyDown : function(event)
9250 // this is a workaround for a password hang bug on chrome/ webkit.
9251 if (this.inputEl().dom.type != 'password') {
9255 var isSelectAll = false;
9257 if(this.inputEl().dom.selectionEnd > 0){
9258 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9260 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9261 event.preventDefault();
9266 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9268 event.preventDefault();
9269 // this is very hacky as keydown always get's upper case.
9271 var cc = String.fromCharCode(event.getCharCode());
9272 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9276 adjustWidth : function(tag, w){
9277 tag = tag.toLowerCase();
9278 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9279 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9283 if(tag == 'textarea'){
9286 }else if(Roo.isOpera){
9290 if(tag == 'textarea'){
9309 * @class Roo.bootstrap.TextArea
9310 * @extends Roo.bootstrap.Input
9311 * Bootstrap TextArea class
9312 * @cfg {Number} cols Specifies the visible width of a text area
9313 * @cfg {Number} rows Specifies the visible number of lines in a text area
9314 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9315 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9316 * @cfg {string} html text
9319 * Create a new TextArea
9320 * @param {Object} config The config object
9323 Roo.bootstrap.TextArea = function(config){
9324 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9328 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9338 getAutoCreate : function(){
9340 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9351 value : this.value || '',
9352 html: this.html || '',
9353 cls : 'form-control',
9354 placeholder : this.placeholder || ''
9358 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9359 input.maxLength = this.maxLength;
9363 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9367 input.cols = this.cols;
9370 if (this.readOnly) {
9371 input.readonly = true;
9375 input.name = this.name;
9379 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9383 ['xs','sm','md','lg'].map(function(size){
9384 if (settings[size]) {
9385 cfg.cls += ' col-' + size + '-' + settings[size];
9389 var inputblock = input;
9391 if(this.hasFeedback && !this.allowBlank){
9395 cls: 'glyphicon form-control-feedback'
9399 cls : 'has-feedback',
9408 if (this.before || this.after) {
9411 cls : 'input-group',
9415 inputblock.cn.push({
9417 cls : 'input-group-addon',
9422 inputblock.cn.push(input);
9424 if(this.hasFeedback && !this.allowBlank){
9425 inputblock.cls += ' has-feedback';
9426 inputblock.cn.push(feedback);
9430 inputblock.cn.push({
9432 cls : 'input-group-addon',
9439 if (align ==='left' && this.fieldLabel.length) {
9444 cls : 'control-label',
9445 html : this.fieldLabel
9456 if(this.labelWidth > 12){
9457 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9460 if(this.labelWidth < 13 && this.labelmd == 0){
9461 this.labelmd = this.labelWidth;
9464 if(this.labellg > 0){
9465 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9466 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9469 if(this.labelmd > 0){
9470 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9471 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9474 if(this.labelsm > 0){
9475 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9476 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9479 if(this.labelxs > 0){
9480 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9481 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9484 } else if ( this.fieldLabel.length) {
9489 //cls : 'input-group-addon',
9490 html : this.fieldLabel
9508 if (this.disabled) {
9509 input.disabled=true;
9516 * return the real textarea element.
9518 inputEl: function ()
9520 return this.el.select('textarea.form-control',true).first();
9524 * Clear any invalid styles/messages for this field
9526 clearInvalid : function()
9529 if(!this.el || this.preventMark){ // not rendered
9533 var label = this.el.select('label', true).first();
9534 var icon = this.el.select('i.fa-star', true).first();
9540 this.el.removeClass(this.invalidClass);
9542 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9544 var feedback = this.el.select('.form-control-feedback', true).first();
9547 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9552 this.fireEvent('valid', this);
9556 * Mark this field as valid
9558 markValid : function()
9560 if(!this.el || this.preventMark){ // not rendered
9564 this.el.removeClass([this.invalidClass, this.validClass]);
9566 var feedback = this.el.select('.form-control-feedback', true).first();
9569 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9572 if(this.disabled || this.allowBlank){
9576 var label = this.el.select('label', true).first();
9577 var icon = this.el.select('i.fa-star', true).first();
9583 this.el.addClass(this.validClass);
9585 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9587 var feedback = this.el.select('.form-control-feedback', true).first();
9590 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9591 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9596 this.fireEvent('valid', this);
9600 * Mark this field as invalid
9601 * @param {String} msg The validation message
9603 markInvalid : function(msg)
9605 if(!this.el || this.preventMark){ // not rendered
9609 this.el.removeClass([this.invalidClass, this.validClass]);
9611 var feedback = this.el.select('.form-control-feedback', true).first();
9614 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9617 if(this.disabled || this.allowBlank){
9621 var label = this.el.select('label', true).first();
9622 var icon = this.el.select('i.fa-star', true).first();
9624 if(!this.getValue().length && label && !icon){
9625 this.el.createChild({
9627 cls : 'text-danger fa fa-lg fa-star',
9628 tooltip : 'This field is required',
9629 style : 'margin-right:5px;'
9633 this.el.addClass(this.invalidClass);
9635 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9637 var feedback = this.el.select('.form-control-feedback', true).first();
9640 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9642 if(this.getValue().length || this.forceFeedback){
9643 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9650 this.fireEvent('invalid', this, msg);
9658 * trigger field - base class for combo..
9663 * @class Roo.bootstrap.TriggerField
9664 * @extends Roo.bootstrap.Input
9665 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9666 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9667 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9668 * for which you can provide a custom implementation. For example:
9670 var trigger = new Roo.bootstrap.TriggerField();
9671 trigger.onTriggerClick = myTriggerFn;
9672 trigger.applyTo('my-field');
9675 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9676 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9677 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9678 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9679 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9682 * Create a new TriggerField.
9683 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9684 * to the base TextField)
9686 Roo.bootstrap.TriggerField = function(config){
9687 this.mimicing = false;
9688 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9691 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9693 * @cfg {String} triggerClass A CSS class to apply to the trigger
9696 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9701 * @cfg {Boolean} removable (true|false) special filter default false
9705 /** @cfg {Boolean} grow @hide */
9706 /** @cfg {Number} growMin @hide */
9707 /** @cfg {Number} growMax @hide */
9713 autoSize: Roo.emptyFn,
9720 actionMode : 'wrap',
9725 getAutoCreate : function(){
9727 var align = this.labelAlign || this.parentLabelAlign();
9732 cls: 'form-group' //input-group
9739 type : this.inputType,
9740 cls : 'form-control',
9741 autocomplete: 'new-password',
9742 placeholder : this.placeholder || ''
9746 input.name = this.name;
9749 input.cls += ' input-' + this.size;
9752 if (this.disabled) {
9753 input.disabled=true;
9756 var inputblock = input;
9758 if(this.hasFeedback && !this.allowBlank){
9762 cls: 'glyphicon form-control-feedback'
9765 if(this.removable && !this.editable && !this.tickable){
9767 cls : 'has-feedback',
9773 cls : 'roo-combo-removable-btn close'
9780 cls : 'has-feedback',
9789 if(this.removable && !this.editable && !this.tickable){
9791 cls : 'roo-removable',
9797 cls : 'roo-combo-removable-btn close'
9804 if (this.before || this.after) {
9807 cls : 'input-group',
9811 inputblock.cn.push({
9813 cls : 'input-group-addon',
9818 inputblock.cn.push(input);
9820 if(this.hasFeedback && !this.allowBlank){
9821 inputblock.cls += ' has-feedback';
9822 inputblock.cn.push(feedback);
9826 inputblock.cn.push({
9828 cls : 'input-group-addon',
9841 cls: 'form-hidden-field'
9855 cls: 'form-hidden-field'
9859 cls: 'roo-select2-choices',
9863 cls: 'roo-select2-search-field',
9876 cls: 'roo-select2-container input-group',
9881 // cls: 'typeahead typeahead-long dropdown-menu',
9882 // style: 'display:none'
9887 if(!this.multiple && this.showToggleBtn){
9893 if (this.caret != false) {
9896 cls: 'fa fa-' + this.caret
9903 cls : 'input-group-addon btn dropdown-toggle',
9908 cls: 'combobox-clear',
9922 combobox.cls += ' roo-select2-container-multi';
9925 if (align ==='left' && this.fieldLabel.length) {
9927 cfg.cls += ' roo-form-group-label-left';
9932 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9933 tooltip : 'This field is required'
9938 cls : 'control-label',
9939 html : this.fieldLabel
9951 var labelCfg = cfg.cn[1];
9952 var contentCfg = cfg.cn[2];
9954 if(this.indicatorpos == 'right'){
9959 cls : 'control-label',
9963 html : this.fieldLabel
9967 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9968 tooltip : 'This field is required'
9981 labelCfg = cfg.cn[0];
9982 contentCfg = cfg.cn[1];
9985 if(this.labelWidth > 12){
9986 labelCfg.style = "width: " + this.labelWidth + 'px';
9989 if(this.labelWidth < 13 && this.labelmd == 0){
9990 this.labelmd = this.labelWidth;
9993 if(this.labellg > 0){
9994 labelCfg.cls += ' col-lg-' + this.labellg;
9995 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9998 if(this.labelmd > 0){
9999 labelCfg.cls += ' col-md-' + this.labelmd;
10000 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10003 if(this.labelsm > 0){
10004 labelCfg.cls += ' col-sm-' + this.labelsm;
10005 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10008 if(this.labelxs > 0){
10009 labelCfg.cls += ' col-xs-' + this.labelxs;
10010 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10013 } else if ( this.fieldLabel.length) {
10014 // Roo.log(" label");
10018 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10019 tooltip : 'This field is required'
10023 //cls : 'input-group-addon',
10024 html : this.fieldLabel
10032 if(this.indicatorpos == 'right'){
10040 html : this.fieldLabel
10044 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10045 tooltip : 'This field is required'
10058 // Roo.log(" no label && no align");
10065 ['xs','sm','md','lg'].map(function(size){
10066 if (settings[size]) {
10067 cfg.cls += ' col-' + size + '-' + settings[size];
10078 onResize : function(w, h){
10079 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10080 // if(typeof w == 'number'){
10081 // var x = w - this.trigger.getWidth();
10082 // this.inputEl().setWidth(this.adjustWidth('input', x));
10083 // this.trigger.setStyle('left', x+'px');
10088 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10091 getResizeEl : function(){
10092 return this.inputEl();
10096 getPositionEl : function(){
10097 return this.inputEl();
10101 alignErrorIcon : function(){
10102 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10106 initEvents : function(){
10110 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10111 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10112 if(!this.multiple && this.showToggleBtn){
10113 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10114 if(this.hideTrigger){
10115 this.trigger.setDisplayed(false);
10117 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10121 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10124 if(this.removable && !this.editable && !this.tickable){
10125 var close = this.closeTriggerEl();
10128 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10129 close.on('click', this.removeBtnClick, this, close);
10133 //this.trigger.addClassOnOver('x-form-trigger-over');
10134 //this.trigger.addClassOnClick('x-form-trigger-click');
10137 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10141 closeTriggerEl : function()
10143 var close = this.el.select('.roo-combo-removable-btn', true).first();
10144 return close ? close : false;
10147 removeBtnClick : function(e, h, el)
10149 e.preventDefault();
10151 if(this.fireEvent("remove", this) !== false){
10153 this.fireEvent("afterremove", this)
10157 createList : function()
10159 this.list = Roo.get(document.body).createChild({
10161 cls: 'typeahead typeahead-long dropdown-menu',
10162 style: 'display:none'
10165 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10170 initTrigger : function(){
10175 onDestroy : function(){
10177 this.trigger.removeAllListeners();
10178 // this.trigger.remove();
10181 // this.wrap.remove();
10183 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10187 onFocus : function(){
10188 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10190 if(!this.mimicing){
10191 this.wrap.addClass('x-trigger-wrap-focus');
10192 this.mimicing = true;
10193 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10194 if(this.monitorTab){
10195 this.el.on("keydown", this.checkTab, this);
10202 checkTab : function(e){
10203 if(e.getKey() == e.TAB){
10204 this.triggerBlur();
10209 onBlur : function(){
10214 mimicBlur : function(e, t){
10216 if(!this.wrap.contains(t) && this.validateBlur()){
10217 this.triggerBlur();
10223 triggerBlur : function(){
10224 this.mimicing = false;
10225 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10226 if(this.monitorTab){
10227 this.el.un("keydown", this.checkTab, this);
10229 //this.wrap.removeClass('x-trigger-wrap-focus');
10230 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10234 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10235 validateBlur : function(e, t){
10240 onDisable : function(){
10241 this.inputEl().dom.disabled = true;
10242 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10244 // this.wrap.addClass('x-item-disabled');
10249 onEnable : function(){
10250 this.inputEl().dom.disabled = false;
10251 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10253 // this.el.removeClass('x-item-disabled');
10258 onShow : function(){
10259 var ae = this.getActionEl();
10262 ae.dom.style.display = '';
10263 ae.dom.style.visibility = 'visible';
10269 onHide : function(){
10270 var ae = this.getActionEl();
10271 ae.dom.style.display = 'none';
10275 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10276 * by an implementing function.
10278 * @param {EventObject} e
10280 onTriggerClick : Roo.emptyFn
10284 * Ext JS Library 1.1.1
10285 * Copyright(c) 2006-2007, Ext JS, LLC.
10287 * Originally Released Under LGPL - original licence link has changed is not relivant.
10290 * <script type="text/javascript">
10295 * @class Roo.data.SortTypes
10297 * Defines the default sorting (casting?) comparison functions used when sorting data.
10299 Roo.data.SortTypes = {
10301 * Default sort that does nothing
10302 * @param {Mixed} s The value being converted
10303 * @return {Mixed} The comparison value
10305 none : function(s){
10310 * The regular expression used to strip tags
10314 stripTagsRE : /<\/?[^>]+>/gi,
10317 * Strips all HTML tags to sort on text only
10318 * @param {Mixed} s The value being converted
10319 * @return {String} The comparison value
10321 asText : function(s){
10322 return String(s).replace(this.stripTagsRE, "");
10326 * Strips all HTML tags to sort on text only - Case insensitive
10327 * @param {Mixed} s The value being converted
10328 * @return {String} The comparison value
10330 asUCText : function(s){
10331 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10335 * Case insensitive string
10336 * @param {Mixed} s The value being converted
10337 * @return {String} The comparison value
10339 asUCString : function(s) {
10340 return String(s).toUpperCase();
10345 * @param {Mixed} s The value being converted
10346 * @return {Number} The comparison value
10348 asDate : function(s) {
10352 if(s instanceof Date){
10353 return s.getTime();
10355 return Date.parse(String(s));
10360 * @param {Mixed} s The value being converted
10361 * @return {Float} The comparison value
10363 asFloat : function(s) {
10364 var val = parseFloat(String(s).replace(/,/g, ""));
10373 * @param {Mixed} s The value being converted
10374 * @return {Number} The comparison value
10376 asInt : function(s) {
10377 var val = parseInt(String(s).replace(/,/g, ""));
10385 * Ext JS Library 1.1.1
10386 * Copyright(c) 2006-2007, Ext JS, LLC.
10388 * Originally Released Under LGPL - original licence link has changed is not relivant.
10391 * <script type="text/javascript">
10395 * @class Roo.data.Record
10396 * Instances of this class encapsulate both record <em>definition</em> information, and record
10397 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10398 * to access Records cached in an {@link Roo.data.Store} object.<br>
10400 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10401 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10404 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10406 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10407 * {@link #create}. The parameters are the same.
10408 * @param {Array} data An associative Array of data values keyed by the field name.
10409 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10410 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10411 * not specified an integer id is generated.
10413 Roo.data.Record = function(data, id){
10414 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10419 * Generate a constructor for a specific record layout.
10420 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10421 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10422 * Each field definition object may contain the following properties: <ul>
10423 * <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,
10424 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10425 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10426 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10427 * is being used, then this is a string containing the javascript expression to reference the data relative to
10428 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10429 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10430 * this may be omitted.</p></li>
10431 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10432 * <ul><li>auto (Default, implies no conversion)</li>
10437 * <li>date</li></ul></p></li>
10438 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10439 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10440 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10441 * by the Reader into an object that will be stored in the Record. It is passed the
10442 * following parameters:<ul>
10443 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10445 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10447 * <br>usage:<br><pre><code>
10448 var TopicRecord = Roo.data.Record.create(
10449 {name: 'title', mapping: 'topic_title'},
10450 {name: 'author', mapping: 'username'},
10451 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10452 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10453 {name: 'lastPoster', mapping: 'user2'},
10454 {name: 'excerpt', mapping: 'post_text'}
10457 var myNewRecord = new TopicRecord({
10458 title: 'Do my job please',
10461 lastPost: new Date(),
10462 lastPoster: 'Animal',
10463 excerpt: 'No way dude!'
10465 myStore.add(myNewRecord);
10470 Roo.data.Record.create = function(o){
10471 var f = function(){
10472 f.superclass.constructor.apply(this, arguments);
10474 Roo.extend(f, Roo.data.Record);
10475 var p = f.prototype;
10476 p.fields = new Roo.util.MixedCollection(false, function(field){
10479 for(var i = 0, len = o.length; i < len; i++){
10480 p.fields.add(new Roo.data.Field(o[i]));
10482 f.getField = function(name){
10483 return p.fields.get(name);
10488 Roo.data.Record.AUTO_ID = 1000;
10489 Roo.data.Record.EDIT = 'edit';
10490 Roo.data.Record.REJECT = 'reject';
10491 Roo.data.Record.COMMIT = 'commit';
10493 Roo.data.Record.prototype = {
10495 * Readonly flag - true if this record has been modified.
10504 join : function(store){
10505 this.store = store;
10509 * Set the named field to the specified value.
10510 * @param {String} name The name of the field to set.
10511 * @param {Object} value The value to set the field to.
10513 set : function(name, value){
10514 if(this.data[name] == value){
10518 if(!this.modified){
10519 this.modified = {};
10521 if(typeof this.modified[name] == 'undefined'){
10522 this.modified[name] = this.data[name];
10524 this.data[name] = value;
10525 if(!this.editing && this.store){
10526 this.store.afterEdit(this);
10531 * Get the value of the named field.
10532 * @param {String} name The name of the field to get the value of.
10533 * @return {Object} The value of the field.
10535 get : function(name){
10536 return this.data[name];
10540 beginEdit : function(){
10541 this.editing = true;
10542 this.modified = {};
10546 cancelEdit : function(){
10547 this.editing = false;
10548 delete this.modified;
10552 endEdit : function(){
10553 this.editing = false;
10554 if(this.dirty && this.store){
10555 this.store.afterEdit(this);
10560 * Usually called by the {@link Roo.data.Store} which owns the Record.
10561 * Rejects all changes made to the Record since either creation, or the last commit operation.
10562 * Modified fields are reverted to their original values.
10564 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10565 * of reject operations.
10567 reject : function(){
10568 var m = this.modified;
10570 if(typeof m[n] != "function"){
10571 this.data[n] = m[n];
10574 this.dirty = false;
10575 delete this.modified;
10576 this.editing = false;
10578 this.store.afterReject(this);
10583 * Usually called by the {@link Roo.data.Store} which owns the Record.
10584 * Commits all changes made to the Record since either creation, or the last commit operation.
10586 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10587 * of commit operations.
10589 commit : function(){
10590 this.dirty = false;
10591 delete this.modified;
10592 this.editing = false;
10594 this.store.afterCommit(this);
10599 hasError : function(){
10600 return this.error != null;
10604 clearError : function(){
10609 * Creates a copy of this record.
10610 * @param {String} id (optional) A new record id if you don't want to use this record's id
10613 copy : function(newId) {
10614 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10618 * Ext JS Library 1.1.1
10619 * Copyright(c) 2006-2007, Ext JS, LLC.
10621 * Originally Released Under LGPL - original licence link has changed is not relivant.
10624 * <script type="text/javascript">
10630 * @class Roo.data.Store
10631 * @extends Roo.util.Observable
10632 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10633 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10635 * 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
10636 * has no knowledge of the format of the data returned by the Proxy.<br>
10638 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10639 * instances from the data object. These records are cached and made available through accessor functions.
10641 * Creates a new Store.
10642 * @param {Object} config A config object containing the objects needed for the Store to access data,
10643 * and read the data into Records.
10645 Roo.data.Store = function(config){
10646 this.data = new Roo.util.MixedCollection(false);
10647 this.data.getKey = function(o){
10650 this.baseParams = {};
10652 this.paramNames = {
10657 "multisort" : "_multisort"
10660 if(config && config.data){
10661 this.inlineData = config.data;
10662 delete config.data;
10665 Roo.apply(this, config);
10667 if(this.reader){ // reader passed
10668 this.reader = Roo.factory(this.reader, Roo.data);
10669 this.reader.xmodule = this.xmodule || false;
10670 if(!this.recordType){
10671 this.recordType = this.reader.recordType;
10673 if(this.reader.onMetaChange){
10674 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10678 if(this.recordType){
10679 this.fields = this.recordType.prototype.fields;
10681 this.modified = [];
10685 * @event datachanged
10686 * Fires when the data cache has changed, and a widget which is using this Store
10687 * as a Record cache should refresh its view.
10688 * @param {Store} this
10690 datachanged : true,
10692 * @event metachange
10693 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10694 * @param {Store} this
10695 * @param {Object} meta The JSON metadata
10700 * Fires when Records have been added to the Store
10701 * @param {Store} this
10702 * @param {Roo.data.Record[]} records The array of Records added
10703 * @param {Number} index The index at which the record(s) were added
10708 * Fires when a Record has been removed from the Store
10709 * @param {Store} this
10710 * @param {Roo.data.Record} record The Record that was removed
10711 * @param {Number} index The index at which the record was removed
10716 * Fires when a Record has been updated
10717 * @param {Store} this
10718 * @param {Roo.data.Record} record The Record that was updated
10719 * @param {String} operation The update operation being performed. Value may be one of:
10721 Roo.data.Record.EDIT
10722 Roo.data.Record.REJECT
10723 Roo.data.Record.COMMIT
10729 * Fires when the data cache has been cleared.
10730 * @param {Store} this
10734 * @event beforeload
10735 * Fires before a request is made for a new data object. If the beforeload handler returns false
10736 * the load action will be canceled.
10737 * @param {Store} this
10738 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10742 * @event beforeloadadd
10743 * Fires after a new set of Records has been loaded.
10744 * @param {Store} this
10745 * @param {Roo.data.Record[]} records The Records that were loaded
10746 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10748 beforeloadadd : true,
10751 * Fires after a new set of Records has been loaded, before they are added to the store.
10752 * @param {Store} this
10753 * @param {Roo.data.Record[]} records The Records that were loaded
10754 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10755 * @params {Object} return from reader
10759 * @event loadexception
10760 * Fires if an exception occurs in the Proxy during loading.
10761 * Called with the signature of the Proxy's "loadexception" event.
10762 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10765 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10766 * @param {Object} load options
10767 * @param {Object} jsonData from your request (normally this contains the Exception)
10769 loadexception : true
10773 this.proxy = Roo.factory(this.proxy, Roo.data);
10774 this.proxy.xmodule = this.xmodule || false;
10775 this.relayEvents(this.proxy, ["loadexception"]);
10777 this.sortToggle = {};
10778 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10780 Roo.data.Store.superclass.constructor.call(this);
10782 if(this.inlineData){
10783 this.loadData(this.inlineData);
10784 delete this.inlineData;
10788 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10790 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10791 * without a remote query - used by combo/forms at present.
10795 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10798 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10801 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10802 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10805 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10806 * on any HTTP request
10809 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10812 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10816 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10817 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10819 remoteSort : false,
10822 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10823 * loaded or when a record is removed. (defaults to false).
10825 pruneModifiedRecords : false,
10828 lastOptions : null,
10831 * Add Records to the Store and fires the add event.
10832 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10834 add : function(records){
10835 records = [].concat(records);
10836 for(var i = 0, len = records.length; i < len; i++){
10837 records[i].join(this);
10839 var index = this.data.length;
10840 this.data.addAll(records);
10841 this.fireEvent("add", this, records, index);
10845 * Remove a Record from the Store and fires the remove event.
10846 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10848 remove : function(record){
10849 var index = this.data.indexOf(record);
10850 this.data.removeAt(index);
10851 if(this.pruneModifiedRecords){
10852 this.modified.remove(record);
10854 this.fireEvent("remove", this, record, index);
10858 * Remove all Records from the Store and fires the clear event.
10860 removeAll : function(){
10862 if(this.pruneModifiedRecords){
10863 this.modified = [];
10865 this.fireEvent("clear", this);
10869 * Inserts Records to the Store at the given index and fires the add event.
10870 * @param {Number} index The start index at which to insert the passed Records.
10871 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10873 insert : function(index, records){
10874 records = [].concat(records);
10875 for(var i = 0, len = records.length; i < len; i++){
10876 this.data.insert(index, records[i]);
10877 records[i].join(this);
10879 this.fireEvent("add", this, records, index);
10883 * Get the index within the cache of the passed Record.
10884 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10885 * @return {Number} The index of the passed Record. Returns -1 if not found.
10887 indexOf : function(record){
10888 return this.data.indexOf(record);
10892 * Get the index within the cache of the Record with the passed id.
10893 * @param {String} id The id of the Record to find.
10894 * @return {Number} The index of the Record. Returns -1 if not found.
10896 indexOfId : function(id){
10897 return this.data.indexOfKey(id);
10901 * Get the Record with the specified id.
10902 * @param {String} id The id of the Record to find.
10903 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10905 getById : function(id){
10906 return this.data.key(id);
10910 * Get the Record at the specified index.
10911 * @param {Number} index The index of the Record to find.
10912 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10914 getAt : function(index){
10915 return this.data.itemAt(index);
10919 * Returns a range of Records between specified indices.
10920 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10921 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10922 * @return {Roo.data.Record[]} An array of Records
10924 getRange : function(start, end){
10925 return this.data.getRange(start, end);
10929 storeOptions : function(o){
10930 o = Roo.apply({}, o);
10933 this.lastOptions = o;
10937 * Loads the Record cache from the configured Proxy using the configured Reader.
10939 * If using remote paging, then the first load call must specify the <em>start</em>
10940 * and <em>limit</em> properties in the options.params property to establish the initial
10941 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10943 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10944 * and this call will return before the new data has been loaded. Perform any post-processing
10945 * in a callback function, or in a "load" event handler.</strong>
10947 * @param {Object} options An object containing properties which control loading options:<ul>
10948 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10949 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10950 * passed the following arguments:<ul>
10951 * <li>r : Roo.data.Record[]</li>
10952 * <li>options: Options object from the load call</li>
10953 * <li>success: Boolean success indicator</li></ul></li>
10954 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10955 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10958 load : function(options){
10959 options = options || {};
10960 if(this.fireEvent("beforeload", this, options) !== false){
10961 this.storeOptions(options);
10962 var p = Roo.apply(options.params || {}, this.baseParams);
10963 // if meta was not loaded from remote source.. try requesting it.
10964 if (!this.reader.metaFromRemote) {
10965 p._requestMeta = 1;
10967 if(this.sortInfo && this.remoteSort){
10968 var pn = this.paramNames;
10969 p[pn["sort"]] = this.sortInfo.field;
10970 p[pn["dir"]] = this.sortInfo.direction;
10972 if (this.multiSort) {
10973 var pn = this.paramNames;
10974 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10977 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10982 * Reloads the Record cache from the configured Proxy using the configured Reader and
10983 * the options from the last load operation performed.
10984 * @param {Object} options (optional) An object containing properties which may override the options
10985 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10986 * the most recently used options are reused).
10988 reload : function(options){
10989 this.load(Roo.applyIf(options||{}, this.lastOptions));
10993 // Called as a callback by the Reader during a load operation.
10994 loadRecords : function(o, options, success){
10995 if(!o || success === false){
10996 if(success !== false){
10997 this.fireEvent("load", this, [], options, o);
10999 if(options.callback){
11000 options.callback.call(options.scope || this, [], options, false);
11004 // if data returned failure - throw an exception.
11005 if (o.success === false) {
11006 // show a message if no listener is registered.
11007 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11008 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11010 // loadmask wil be hooked into this..
11011 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11014 var r = o.records, t = o.totalRecords || r.length;
11016 this.fireEvent("beforeloadadd", this, r, options, o);
11018 if(!options || options.add !== true){
11019 if(this.pruneModifiedRecords){
11020 this.modified = [];
11022 for(var i = 0, len = r.length; i < len; i++){
11026 this.data = this.snapshot;
11027 delete this.snapshot;
11030 this.data.addAll(r);
11031 this.totalLength = t;
11033 this.fireEvent("datachanged", this);
11035 this.totalLength = Math.max(t, this.data.length+r.length);
11039 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11041 var e = new Roo.data.Record({});
11043 e.set(this.parent.displayField, this.parent.emptyTitle);
11044 e.set(this.parent.valueField, '');
11049 this.fireEvent("load", this, r, options, o);
11050 if(options.callback){
11051 options.callback.call(options.scope || this, r, options, true);
11057 * Loads data from a passed data block. A Reader which understands the format of the data
11058 * must have been configured in the constructor.
11059 * @param {Object} data The data block from which to read the Records. The format of the data expected
11060 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11061 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11063 loadData : function(o, append){
11064 var r = this.reader.readRecords(o);
11065 this.loadRecords(r, {add: append}, true);
11069 * Gets the number of cached records.
11071 * <em>If using paging, this may not be the total size of the dataset. If the data object
11072 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11073 * the data set size</em>
11075 getCount : function(){
11076 return this.data.length || 0;
11080 * Gets the total number of records in the dataset as returned by the server.
11082 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11083 * the dataset size</em>
11085 getTotalCount : function(){
11086 return this.totalLength || 0;
11090 * Returns the sort state of the Store as an object with two properties:
11092 field {String} The name of the field by which the Records are sorted
11093 direction {String} The sort order, "ASC" or "DESC"
11096 getSortState : function(){
11097 return this.sortInfo;
11101 applySort : function(){
11102 if(this.sortInfo && !this.remoteSort){
11103 var s = this.sortInfo, f = s.field;
11104 var st = this.fields.get(f).sortType;
11105 var fn = function(r1, r2){
11106 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11107 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11109 this.data.sort(s.direction, fn);
11110 if(this.snapshot && this.snapshot != this.data){
11111 this.snapshot.sort(s.direction, fn);
11117 * Sets the default sort column and order to be used by the next load operation.
11118 * @param {String} fieldName The name of the field to sort by.
11119 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11121 setDefaultSort : function(field, dir){
11122 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11126 * Sort the Records.
11127 * If remote sorting is used, the sort is performed on the server, and the cache is
11128 * reloaded. If local sorting is used, the cache is sorted internally.
11129 * @param {String} fieldName The name of the field to sort by.
11130 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11132 sort : function(fieldName, dir){
11133 var f = this.fields.get(fieldName);
11135 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11137 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11138 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11143 this.sortToggle[f.name] = dir;
11144 this.sortInfo = {field: f.name, direction: dir};
11145 if(!this.remoteSort){
11147 this.fireEvent("datachanged", this);
11149 this.load(this.lastOptions);
11154 * Calls the specified function for each of the Records in the cache.
11155 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11156 * Returning <em>false</em> aborts and exits the iteration.
11157 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11159 each : function(fn, scope){
11160 this.data.each(fn, scope);
11164 * Gets all records modified since the last commit. Modified records are persisted across load operations
11165 * (e.g., during paging).
11166 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11168 getModifiedRecords : function(){
11169 return this.modified;
11173 createFilterFn : function(property, value, anyMatch){
11174 if(!value.exec){ // not a regex
11175 value = String(value);
11176 if(value.length == 0){
11179 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11181 return function(r){
11182 return value.test(r.data[property]);
11187 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11188 * @param {String} property A field on your records
11189 * @param {Number} start The record index to start at (defaults to 0)
11190 * @param {Number} end The last record index to include (defaults to length - 1)
11191 * @return {Number} The sum
11193 sum : function(property, start, end){
11194 var rs = this.data.items, v = 0;
11195 start = start || 0;
11196 end = (end || end === 0) ? end : rs.length-1;
11198 for(var i = start; i <= end; i++){
11199 v += (rs[i].data[property] || 0);
11205 * Filter the records by a specified property.
11206 * @param {String} field A field on your records
11207 * @param {String/RegExp} value Either a string that the field
11208 * should start with or a RegExp to test against the field
11209 * @param {Boolean} anyMatch True to match any part not just the beginning
11211 filter : function(property, value, anyMatch){
11212 var fn = this.createFilterFn(property, value, anyMatch);
11213 return fn ? this.filterBy(fn) : this.clearFilter();
11217 * Filter by a function. The specified function will be called with each
11218 * record in this data source. If the function returns true the record is included,
11219 * otherwise it is filtered.
11220 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11221 * @param {Object} scope (optional) The scope of the function (defaults to this)
11223 filterBy : function(fn, scope){
11224 this.snapshot = this.snapshot || this.data;
11225 this.data = this.queryBy(fn, scope||this);
11226 this.fireEvent("datachanged", this);
11230 * Query the records by a specified property.
11231 * @param {String} field A field on your records
11232 * @param {String/RegExp} value Either a string that the field
11233 * should start with or a RegExp to test against the field
11234 * @param {Boolean} anyMatch True to match any part not just the beginning
11235 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11237 query : function(property, value, anyMatch){
11238 var fn = this.createFilterFn(property, value, anyMatch);
11239 return fn ? this.queryBy(fn) : this.data.clone();
11243 * Query by a function. The specified function will be called with each
11244 * record in this data source. If the function returns true the record is included
11246 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11247 * @param {Object} scope (optional) The scope of the function (defaults to this)
11248 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11250 queryBy : function(fn, scope){
11251 var data = this.snapshot || this.data;
11252 return data.filterBy(fn, scope||this);
11256 * Collects unique values for a particular dataIndex from this store.
11257 * @param {String} dataIndex The property to collect
11258 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11259 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11260 * @return {Array} An array of the unique values
11262 collect : function(dataIndex, allowNull, bypassFilter){
11263 var d = (bypassFilter === true && this.snapshot) ?
11264 this.snapshot.items : this.data.items;
11265 var v, sv, r = [], l = {};
11266 for(var i = 0, len = d.length; i < len; i++){
11267 v = d[i].data[dataIndex];
11269 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11278 * Revert to a view of the Record cache with no filtering applied.
11279 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11281 clearFilter : function(suppressEvent){
11282 if(this.snapshot && this.snapshot != this.data){
11283 this.data = this.snapshot;
11284 delete this.snapshot;
11285 if(suppressEvent !== true){
11286 this.fireEvent("datachanged", this);
11292 afterEdit : function(record){
11293 if(this.modified.indexOf(record) == -1){
11294 this.modified.push(record);
11296 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11300 afterReject : function(record){
11301 this.modified.remove(record);
11302 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11306 afterCommit : function(record){
11307 this.modified.remove(record);
11308 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11312 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11313 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11315 commitChanges : function(){
11316 var m = this.modified.slice(0);
11317 this.modified = [];
11318 for(var i = 0, len = m.length; i < len; i++){
11324 * Cancel outstanding changes on all changed records.
11326 rejectChanges : function(){
11327 var m = this.modified.slice(0);
11328 this.modified = [];
11329 for(var i = 0, len = m.length; i < len; i++){
11334 onMetaChange : function(meta, rtype, o){
11335 this.recordType = rtype;
11336 this.fields = rtype.prototype.fields;
11337 delete this.snapshot;
11338 this.sortInfo = meta.sortInfo || this.sortInfo;
11339 this.modified = [];
11340 this.fireEvent('metachange', this, this.reader.meta);
11343 moveIndex : function(data, type)
11345 var index = this.indexOf(data);
11347 var newIndex = index + type;
11351 this.insert(newIndex, data);
11356 * Ext JS Library 1.1.1
11357 * Copyright(c) 2006-2007, Ext JS, LLC.
11359 * Originally Released Under LGPL - original licence link has changed is not relivant.
11362 * <script type="text/javascript">
11366 * @class Roo.data.SimpleStore
11367 * @extends Roo.data.Store
11368 * Small helper class to make creating Stores from Array data easier.
11369 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11370 * @cfg {Array} fields An array of field definition objects, or field name strings.
11371 * @cfg {Array} data The multi-dimensional array of data
11373 * @param {Object} config
11375 Roo.data.SimpleStore = function(config){
11376 Roo.data.SimpleStore.superclass.constructor.call(this, {
11378 reader: new Roo.data.ArrayReader({
11381 Roo.data.Record.create(config.fields)
11383 proxy : new Roo.data.MemoryProxy(config.data)
11387 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11389 * Ext JS Library 1.1.1
11390 * Copyright(c) 2006-2007, Ext JS, LLC.
11392 * Originally Released Under LGPL - original licence link has changed is not relivant.
11395 * <script type="text/javascript">
11400 * @extends Roo.data.Store
11401 * @class Roo.data.JsonStore
11402 * Small helper class to make creating Stores for JSON data easier. <br/>
11404 var store = new Roo.data.JsonStore({
11405 url: 'get-images.php',
11407 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11410 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11411 * JsonReader and HttpProxy (unless inline data is provided).</b>
11412 * @cfg {Array} fields An array of field definition objects, or field name strings.
11414 * @param {Object} config
11416 Roo.data.JsonStore = function(c){
11417 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11418 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11419 reader: new Roo.data.JsonReader(c, c.fields)
11422 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11424 * Ext JS Library 1.1.1
11425 * Copyright(c) 2006-2007, Ext JS, LLC.
11427 * Originally Released Under LGPL - original licence link has changed is not relivant.
11430 * <script type="text/javascript">
11434 Roo.data.Field = function(config){
11435 if(typeof config == "string"){
11436 config = {name: config};
11438 Roo.apply(this, config);
11441 this.type = "auto";
11444 var st = Roo.data.SortTypes;
11445 // named sortTypes are supported, here we look them up
11446 if(typeof this.sortType == "string"){
11447 this.sortType = st[this.sortType];
11450 // set default sortType for strings and dates
11451 if(!this.sortType){
11454 this.sortType = st.asUCString;
11457 this.sortType = st.asDate;
11460 this.sortType = st.none;
11465 var stripRe = /[\$,%]/g;
11467 // prebuilt conversion function for this field, instead of
11468 // switching every time we're reading a value
11470 var cv, dateFormat = this.dateFormat;
11475 cv = function(v){ return v; };
11478 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11482 return v !== undefined && v !== null && v !== '' ?
11483 parseInt(String(v).replace(stripRe, ""), 10) : '';
11488 return v !== undefined && v !== null && v !== '' ?
11489 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11494 cv = function(v){ return v === true || v === "true" || v == 1; };
11501 if(v instanceof Date){
11505 if(dateFormat == "timestamp"){
11506 return new Date(v*1000);
11508 return Date.parseDate(v, dateFormat);
11510 var parsed = Date.parse(v);
11511 return parsed ? new Date(parsed) : null;
11520 Roo.data.Field.prototype = {
11528 * Ext JS Library 1.1.1
11529 * Copyright(c) 2006-2007, Ext JS, LLC.
11531 * Originally Released Under LGPL - original licence link has changed is not relivant.
11534 * <script type="text/javascript">
11537 // Base class for reading structured data from a data source. This class is intended to be
11538 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11541 * @class Roo.data.DataReader
11542 * Base class for reading structured data from a data source. This class is intended to be
11543 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11546 Roo.data.DataReader = function(meta, recordType){
11550 this.recordType = recordType instanceof Array ?
11551 Roo.data.Record.create(recordType) : recordType;
11554 Roo.data.DataReader.prototype = {
11556 * Create an empty record
11557 * @param {Object} data (optional) - overlay some values
11558 * @return {Roo.data.Record} record created.
11560 newRow : function(d) {
11562 this.recordType.prototype.fields.each(function(c) {
11564 case 'int' : da[c.name] = 0; break;
11565 case 'date' : da[c.name] = new Date(); break;
11566 case 'float' : da[c.name] = 0.0; break;
11567 case 'boolean' : da[c.name] = false; break;
11568 default : da[c.name] = ""; break;
11572 return new this.recordType(Roo.apply(da, d));
11577 * Ext JS Library 1.1.1
11578 * Copyright(c) 2006-2007, Ext JS, LLC.
11580 * Originally Released Under LGPL - original licence link has changed is not relivant.
11583 * <script type="text/javascript">
11587 * @class Roo.data.DataProxy
11588 * @extends Roo.data.Observable
11589 * This class is an abstract base class for implementations which provide retrieval of
11590 * unformatted data objects.<br>
11592 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11593 * (of the appropriate type which knows how to parse the data object) to provide a block of
11594 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11596 * Custom implementations must implement the load method as described in
11597 * {@link Roo.data.HttpProxy#load}.
11599 Roo.data.DataProxy = function(){
11602 * @event beforeload
11603 * Fires before a network request is made to retrieve a data object.
11604 * @param {Object} This DataProxy object.
11605 * @param {Object} params The params parameter to the load function.
11610 * Fires before the load method's callback is called.
11611 * @param {Object} This DataProxy object.
11612 * @param {Object} o The data object.
11613 * @param {Object} arg The callback argument object passed to the load function.
11617 * @event loadexception
11618 * Fires if an Exception occurs during data retrieval.
11619 * @param {Object} This DataProxy object.
11620 * @param {Object} o The data object.
11621 * @param {Object} arg The callback argument object passed to the load function.
11622 * @param {Object} e The Exception.
11624 loadexception : true
11626 Roo.data.DataProxy.superclass.constructor.call(this);
11629 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11632 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11636 * Ext JS Library 1.1.1
11637 * Copyright(c) 2006-2007, Ext JS, LLC.
11639 * Originally Released Under LGPL - original licence link has changed is not relivant.
11642 * <script type="text/javascript">
11645 * @class Roo.data.MemoryProxy
11646 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11647 * to the Reader when its load method is called.
11649 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11651 Roo.data.MemoryProxy = function(data){
11655 Roo.data.MemoryProxy.superclass.constructor.call(this);
11659 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11662 * Load data from the requested source (in this case an in-memory
11663 * data object passed to the constructor), read the data object into
11664 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11665 * process that block using the passed callback.
11666 * @param {Object} params This parameter is not used by the MemoryProxy class.
11667 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11668 * object into a block of Roo.data.Records.
11669 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11670 * The function must be passed <ul>
11671 * <li>The Record block object</li>
11672 * <li>The "arg" argument from the load function</li>
11673 * <li>A boolean success indicator</li>
11675 * @param {Object} scope The scope in which to call the callback
11676 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11678 load : function(params, reader, callback, scope, arg){
11679 params = params || {};
11682 result = reader.readRecords(this.data);
11684 this.fireEvent("loadexception", this, arg, null, e);
11685 callback.call(scope, null, arg, false);
11688 callback.call(scope, result, arg, true);
11692 update : function(params, records){
11697 * Ext JS Library 1.1.1
11698 * Copyright(c) 2006-2007, Ext JS, LLC.
11700 * Originally Released Under LGPL - original licence link has changed is not relivant.
11703 * <script type="text/javascript">
11706 * @class Roo.data.HttpProxy
11707 * @extends Roo.data.DataProxy
11708 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11709 * configured to reference a certain URL.<br><br>
11711 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11712 * from which the running page was served.<br><br>
11714 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11716 * Be aware that to enable the browser to parse an XML document, the server must set
11717 * the Content-Type header in the HTTP response to "text/xml".
11719 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11720 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11721 * will be used to make the request.
11723 Roo.data.HttpProxy = function(conn){
11724 Roo.data.HttpProxy.superclass.constructor.call(this);
11725 // is conn a conn config or a real conn?
11727 this.useAjax = !conn || !conn.events;
11731 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11732 // thse are take from connection...
11735 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11738 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11739 * extra parameters to each request made by this object. (defaults to undefined)
11742 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11743 * to each request made by this object. (defaults to undefined)
11746 * @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)
11749 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11752 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11758 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11762 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11763 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11764 * a finer-grained basis than the DataProxy events.
11766 getConnection : function(){
11767 return this.useAjax ? Roo.Ajax : this.conn;
11771 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11772 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11773 * process that block using the passed callback.
11774 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11775 * for the request to the remote server.
11776 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11777 * object into a block of Roo.data.Records.
11778 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11779 * The function must be passed <ul>
11780 * <li>The Record block object</li>
11781 * <li>The "arg" argument from the load function</li>
11782 * <li>A boolean success indicator</li>
11784 * @param {Object} scope The scope in which to call the callback
11785 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11787 load : function(params, reader, callback, scope, arg){
11788 if(this.fireEvent("beforeload", this, params) !== false){
11790 params : params || {},
11792 callback : callback,
11797 callback : this.loadResponse,
11801 Roo.applyIf(o, this.conn);
11802 if(this.activeRequest){
11803 Roo.Ajax.abort(this.activeRequest);
11805 this.activeRequest = Roo.Ajax.request(o);
11807 this.conn.request(o);
11810 callback.call(scope||this, null, arg, false);
11815 loadResponse : function(o, success, response){
11816 delete this.activeRequest;
11818 this.fireEvent("loadexception", this, o, response);
11819 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11824 result = o.reader.read(response);
11826 this.fireEvent("loadexception", this, o, response, e);
11827 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11831 this.fireEvent("load", this, o, o.request.arg);
11832 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11836 update : function(dataSet){
11841 updateResponse : function(dataSet){
11846 * Ext JS Library 1.1.1
11847 * Copyright(c) 2006-2007, Ext JS, LLC.
11849 * Originally Released Under LGPL - original licence link has changed is not relivant.
11852 * <script type="text/javascript">
11856 * @class Roo.data.ScriptTagProxy
11857 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11858 * other than the originating domain of the running page.<br><br>
11860 * <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
11861 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11863 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11864 * source code that is used as the source inside a <script> tag.<br><br>
11866 * In order for the browser to process the returned data, the server must wrap the data object
11867 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11868 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11869 * depending on whether the callback name was passed:
11872 boolean scriptTag = false;
11873 String cb = request.getParameter("callback");
11876 response.setContentType("text/javascript");
11878 response.setContentType("application/x-json");
11880 Writer out = response.getWriter();
11882 out.write(cb + "(");
11884 out.print(dataBlock.toJsonString());
11891 * @param {Object} config A configuration object.
11893 Roo.data.ScriptTagProxy = function(config){
11894 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11895 Roo.apply(this, config);
11896 this.head = document.getElementsByTagName("head")[0];
11899 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11901 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11903 * @cfg {String} url The URL from which to request the data object.
11906 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11910 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11911 * the server the name of the callback function set up by the load call to process the returned data object.
11912 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11913 * javascript output which calls this named function passing the data object as its only parameter.
11915 callbackParam : "callback",
11917 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11918 * name to the request.
11923 * Load data from the configured URL, read the data object into
11924 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11925 * process that block using the passed callback.
11926 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11927 * for the request to the remote server.
11928 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11929 * object into a block of Roo.data.Records.
11930 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11931 * The function must be passed <ul>
11932 * <li>The Record block object</li>
11933 * <li>The "arg" argument from the load function</li>
11934 * <li>A boolean success indicator</li>
11936 * @param {Object} scope The scope in which to call the callback
11937 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11939 load : function(params, reader, callback, scope, arg){
11940 if(this.fireEvent("beforeload", this, params) !== false){
11942 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11944 var url = this.url;
11945 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11947 url += "&_dc=" + (new Date().getTime());
11949 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11952 cb : "stcCallback"+transId,
11953 scriptId : "stcScript"+transId,
11957 callback : callback,
11963 window[trans.cb] = function(o){
11964 conn.handleResponse(o, trans);
11967 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11969 if(this.autoAbort !== false){
11973 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11975 var script = document.createElement("script");
11976 script.setAttribute("src", url);
11977 script.setAttribute("type", "text/javascript");
11978 script.setAttribute("id", trans.scriptId);
11979 this.head.appendChild(script);
11981 this.trans = trans;
11983 callback.call(scope||this, null, arg, false);
11988 isLoading : function(){
11989 return this.trans ? true : false;
11993 * Abort the current server request.
11995 abort : function(){
11996 if(this.isLoading()){
11997 this.destroyTrans(this.trans);
12002 destroyTrans : function(trans, isLoaded){
12003 this.head.removeChild(document.getElementById(trans.scriptId));
12004 clearTimeout(trans.timeoutId);
12006 window[trans.cb] = undefined;
12008 delete window[trans.cb];
12011 // if hasn't been loaded, wait for load to remove it to prevent script error
12012 window[trans.cb] = function(){
12013 window[trans.cb] = undefined;
12015 delete window[trans.cb];
12022 handleResponse : function(o, trans){
12023 this.trans = false;
12024 this.destroyTrans(trans, true);
12027 result = trans.reader.readRecords(o);
12029 this.fireEvent("loadexception", this, o, trans.arg, e);
12030 trans.callback.call(trans.scope||window, null, trans.arg, false);
12033 this.fireEvent("load", this, o, trans.arg);
12034 trans.callback.call(trans.scope||window, result, trans.arg, true);
12038 handleFailure : function(trans){
12039 this.trans = false;
12040 this.destroyTrans(trans, false);
12041 this.fireEvent("loadexception", this, null, trans.arg);
12042 trans.callback.call(trans.scope||window, null, trans.arg, false);
12046 * Ext JS Library 1.1.1
12047 * Copyright(c) 2006-2007, Ext JS, LLC.
12049 * Originally Released Under LGPL - original licence link has changed is not relivant.
12052 * <script type="text/javascript">
12056 * @class Roo.data.JsonReader
12057 * @extends Roo.data.DataReader
12058 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12059 * based on mappings in a provided Roo.data.Record constructor.
12061 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12062 * in the reply previously.
12067 var RecordDef = Roo.data.Record.create([
12068 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12069 {name: 'occupation'} // This field will use "occupation" as the mapping.
12071 var myReader = new Roo.data.JsonReader({
12072 totalProperty: "results", // The property which contains the total dataset size (optional)
12073 root: "rows", // The property which contains an Array of row objects
12074 id: "id" // The property within each row object that provides an ID for the record (optional)
12078 * This would consume a JSON file like this:
12080 { 'results': 2, 'rows': [
12081 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12082 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12085 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12086 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12087 * paged from the remote server.
12088 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12089 * @cfg {String} root name of the property which contains the Array of row objects.
12090 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12091 * @cfg {Array} fields Array of field definition objects
12093 * Create a new JsonReader
12094 * @param {Object} meta Metadata configuration options
12095 * @param {Object} recordType Either an Array of field definition objects,
12096 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12098 Roo.data.JsonReader = function(meta, recordType){
12101 // set some defaults:
12102 Roo.applyIf(meta, {
12103 totalProperty: 'total',
12104 successProperty : 'success',
12109 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12111 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12114 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12115 * Used by Store query builder to append _requestMeta to params.
12118 metaFromRemote : false,
12120 * This method is only used by a DataProxy which has retrieved data from a remote server.
12121 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12122 * @return {Object} data A data block which is used by an Roo.data.Store object as
12123 * a cache of Roo.data.Records.
12125 read : function(response){
12126 var json = response.responseText;
12128 var o = /* eval:var:o */ eval("("+json+")");
12130 throw {message: "JsonReader.read: Json object not found"};
12136 this.metaFromRemote = true;
12137 this.meta = o.metaData;
12138 this.recordType = Roo.data.Record.create(o.metaData.fields);
12139 this.onMetaChange(this.meta, this.recordType, o);
12141 return this.readRecords(o);
12144 // private function a store will implement
12145 onMetaChange : function(meta, recordType, o){
12152 simpleAccess: function(obj, subsc) {
12159 getJsonAccessor: function(){
12161 return function(expr) {
12163 return(re.test(expr))
12164 ? new Function("obj", "return obj." + expr)
12169 return Roo.emptyFn;
12174 * Create a data block containing Roo.data.Records from an XML document.
12175 * @param {Object} o An object which contains an Array of row objects in the property specified
12176 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12177 * which contains the total size of the dataset.
12178 * @return {Object} data A data block which is used by an Roo.data.Store object as
12179 * a cache of Roo.data.Records.
12181 readRecords : function(o){
12183 * After any data loads, the raw JSON data is available for further custom processing.
12187 var s = this.meta, Record = this.recordType,
12188 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12190 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12192 if(s.totalProperty) {
12193 this.getTotal = this.getJsonAccessor(s.totalProperty);
12195 if(s.successProperty) {
12196 this.getSuccess = this.getJsonAccessor(s.successProperty);
12198 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12200 var g = this.getJsonAccessor(s.id);
12201 this.getId = function(rec) {
12203 return (r === undefined || r === "") ? null : r;
12206 this.getId = function(){return null;};
12209 for(var jj = 0; jj < fl; jj++){
12211 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12212 this.ef[jj] = this.getJsonAccessor(map);
12216 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12217 if(s.totalProperty){
12218 var vt = parseInt(this.getTotal(o), 10);
12223 if(s.successProperty){
12224 var vs = this.getSuccess(o);
12225 if(vs === false || vs === 'false'){
12230 for(var i = 0; i < c; i++){
12233 var id = this.getId(n);
12234 for(var j = 0; j < fl; j++){
12236 var v = this.ef[j](n);
12238 Roo.log('missing convert for ' + f.name);
12242 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12244 var record = new Record(values, id);
12246 records[i] = record;
12252 totalRecords : totalRecords
12257 * Ext JS Library 1.1.1
12258 * Copyright(c) 2006-2007, Ext JS, LLC.
12260 * Originally Released Under LGPL - original licence link has changed is not relivant.
12263 * <script type="text/javascript">
12267 * @class Roo.data.ArrayReader
12268 * @extends Roo.data.DataReader
12269 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12270 * Each element of that Array represents a row of data fields. The
12271 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12272 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12276 var RecordDef = Roo.data.Record.create([
12277 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12278 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12280 var myReader = new Roo.data.ArrayReader({
12281 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12285 * This would consume an Array like this:
12287 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12289 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12291 * Create a new JsonReader
12292 * @param {Object} meta Metadata configuration options.
12293 * @param {Object} recordType Either an Array of field definition objects
12294 * as specified to {@link Roo.data.Record#create},
12295 * or an {@link Roo.data.Record} object
12296 * created using {@link Roo.data.Record#create}.
12298 Roo.data.ArrayReader = function(meta, recordType){
12299 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12302 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12304 * Create a data block containing Roo.data.Records from an XML document.
12305 * @param {Object} o An Array of row objects which represents the dataset.
12306 * @return {Object} data A data block which is used by an Roo.data.Store object as
12307 * a cache of Roo.data.Records.
12309 readRecords : function(o){
12310 var sid = this.meta ? this.meta.id : null;
12311 var recordType = this.recordType, fields = recordType.prototype.fields;
12314 for(var i = 0; i < root.length; i++){
12317 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12318 for(var j = 0, jlen = fields.length; j < jlen; j++){
12319 var f = fields.items[j];
12320 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12321 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12323 values[f.name] = v;
12325 var record = new recordType(values, id);
12327 records[records.length] = record;
12331 totalRecords : records.length
12340 * @class Roo.bootstrap.ComboBox
12341 * @extends Roo.bootstrap.TriggerField
12342 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12343 * @cfg {Boolean} append (true|false) default false
12344 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12345 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12346 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12347 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12348 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12349 * @cfg {Boolean} animate default true
12350 * @cfg {Boolean} emptyResultText only for touch device
12351 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12352 * @cfg {String} emptyTitle default ''
12354 * Create a new ComboBox.
12355 * @param {Object} config Configuration options
12357 Roo.bootstrap.ComboBox = function(config){
12358 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12362 * Fires when the dropdown list is expanded
12363 * @param {Roo.bootstrap.ComboBox} combo This combo box
12368 * Fires when the dropdown list is collapsed
12369 * @param {Roo.bootstrap.ComboBox} combo This combo box
12373 * @event beforeselect
12374 * Fires before a list item is selected. Return false to cancel the selection.
12375 * @param {Roo.bootstrap.ComboBox} combo This combo box
12376 * @param {Roo.data.Record} record The data record returned from the underlying store
12377 * @param {Number} index The index of the selected item in the dropdown list
12379 'beforeselect' : true,
12382 * Fires when a list item is selected
12383 * @param {Roo.bootstrap.ComboBox} combo This combo box
12384 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12385 * @param {Number} index The index of the selected item in the dropdown list
12389 * @event beforequery
12390 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12391 * The event object passed has these properties:
12392 * @param {Roo.bootstrap.ComboBox} combo This combo box
12393 * @param {String} query The query
12394 * @param {Boolean} forceAll true to force "all" query
12395 * @param {Boolean} cancel true to cancel the query
12396 * @param {Object} e The query event object
12398 'beforequery': true,
12401 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12402 * @param {Roo.bootstrap.ComboBox} combo This combo box
12407 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12408 * @param {Roo.bootstrap.ComboBox} combo This combo box
12409 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12414 * Fires when the remove value from the combobox array
12415 * @param {Roo.bootstrap.ComboBox} combo This combo box
12419 * @event afterremove
12420 * Fires when the remove value from the combobox array
12421 * @param {Roo.bootstrap.ComboBox} combo This combo box
12423 'afterremove' : true,
12425 * @event specialfilter
12426 * Fires when specialfilter
12427 * @param {Roo.bootstrap.ComboBox} combo This combo box
12429 'specialfilter' : true,
12432 * Fires when tick the element
12433 * @param {Roo.bootstrap.ComboBox} combo This combo box
12437 * @event touchviewdisplay
12438 * Fires when touch view require special display (default is using displayField)
12439 * @param {Roo.bootstrap.ComboBox} combo This combo box
12440 * @param {Object} cfg set html .
12442 'touchviewdisplay' : true
12447 this.tickItems = [];
12449 this.selectedIndex = -1;
12450 if(this.mode == 'local'){
12451 if(config.queryDelay === undefined){
12452 this.queryDelay = 10;
12454 if(config.minChars === undefined){
12460 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12463 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12464 * rendering into an Roo.Editor, defaults to false)
12467 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12468 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12471 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12474 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12475 * the dropdown list (defaults to undefined, with no header element)
12479 * @cfg {String/Roo.Template} tpl The template to use to render the output
12483 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12485 listWidth: undefined,
12487 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12488 * mode = 'remote' or 'text' if mode = 'local')
12490 displayField: undefined,
12493 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12494 * mode = 'remote' or 'value' if mode = 'local').
12495 * Note: use of a valueField requires the user make a selection
12496 * in order for a value to be mapped.
12498 valueField: undefined,
12500 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12505 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12506 * field's data value (defaults to the underlying DOM element's name)
12508 hiddenName: undefined,
12510 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12514 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12516 selectedClass: 'active',
12519 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12523 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12524 * anchor positions (defaults to 'tl-bl')
12526 listAlign: 'tl-bl?',
12528 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12532 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12533 * query specified by the allQuery config option (defaults to 'query')
12535 triggerAction: 'query',
12537 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12538 * (defaults to 4, does not apply if editable = false)
12542 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12543 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12547 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12548 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12552 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12553 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12557 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12558 * when editable = true (defaults to false)
12560 selectOnFocus:false,
12562 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12564 queryParam: 'query',
12566 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12567 * when mode = 'remote' (defaults to 'Loading...')
12569 loadingText: 'Loading...',
12571 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12575 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12579 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12580 * traditional select (defaults to true)
12584 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12588 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12592 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12593 * listWidth has a higher value)
12597 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12598 * allow the user to set arbitrary text into the field (defaults to false)
12600 forceSelection:false,
12602 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12603 * if typeAhead = true (defaults to 250)
12605 typeAheadDelay : 250,
12607 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12608 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12610 valueNotFoundText : undefined,
12612 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12614 blockFocus : false,
12617 * @cfg {Boolean} disableClear Disable showing of clear button.
12619 disableClear : false,
12621 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12623 alwaysQuery : false,
12626 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12631 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12633 invalidClass : "has-warning",
12636 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12638 validClass : "has-success",
12641 * @cfg {Boolean} specialFilter (true|false) special filter default false
12643 specialFilter : false,
12646 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12648 mobileTouchView : true,
12651 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12653 useNativeIOS : false,
12655 ios_options : false,
12667 btnPosition : 'right',
12668 triggerList : true,
12669 showToggleBtn : true,
12671 emptyResultText: 'Empty',
12672 triggerText : 'Select',
12675 // element that contains real text value.. (when hidden is used..)
12677 getAutoCreate : function()
12682 * Render classic select for iso
12685 if(Roo.isIOS && this.useNativeIOS){
12686 cfg = this.getAutoCreateNativeIOS();
12694 if(Roo.isTouch && this.mobileTouchView){
12695 cfg = this.getAutoCreateTouchView();
12702 if(!this.tickable){
12703 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12704 if(this.name == 'info_year_invest_id_display_name'){
12705 Roo.log('cfg.................................................');
12712 * ComboBox with tickable selections
12715 var align = this.labelAlign || this.parentLabelAlign();
12718 cls : 'form-group roo-combobox-tickable' //input-group
12721 var btn_text_select = '';
12722 var btn_text_done = '';
12723 var btn_text_cancel = '';
12725 if (this.btn_text_show) {
12726 btn_text_select = 'Select';
12727 btn_text_done = 'Done';
12728 btn_text_cancel = 'Cancel';
12733 cls : 'tickable-buttons',
12738 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12739 //html : this.triggerText
12740 html: btn_text_select
12746 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12748 html: btn_text_done
12754 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12756 html: btn_text_cancel
12762 buttons.cn.unshift({
12764 cls: 'roo-select2-search-field-input'
12770 Roo.each(buttons.cn, function(c){
12772 c.cls += ' btn-' + _this.size;
12775 if (_this.disabled) {
12786 cls: 'form-hidden-field'
12790 cls: 'roo-select2-choices',
12794 cls: 'roo-select2-search-field',
12805 cls: 'roo-select2-container input-group roo-select2-container-multi',
12810 // cls: 'typeahead typeahead-long dropdown-menu',
12811 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12816 if(this.hasFeedback && !this.allowBlank){
12820 cls: 'glyphicon form-control-feedback'
12823 combobox.cn.push(feedback);
12827 if (align ==='left' && this.fieldLabel.length) {
12829 cfg.cls += ' roo-form-group-label-left';
12834 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12835 tooltip : 'This field is required'
12840 cls : 'control-label',
12841 html : this.fieldLabel
12853 var labelCfg = cfg.cn[1];
12854 var contentCfg = cfg.cn[2];
12857 if(this.indicatorpos == 'right'){
12863 cls : 'control-label',
12867 html : this.fieldLabel
12871 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12872 tooltip : 'This field is required'
12887 labelCfg = cfg.cn[0];
12888 contentCfg = cfg.cn[1];
12892 if(this.labelWidth > 12){
12893 labelCfg.style = "width: " + this.labelWidth + 'px';
12896 if(this.labelWidth < 13 && this.labelmd == 0){
12897 this.labelmd = this.labelWidth;
12900 if(this.labellg > 0){
12901 labelCfg.cls += ' col-lg-' + this.labellg;
12902 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12905 if(this.labelmd > 0){
12906 labelCfg.cls += ' col-md-' + this.labelmd;
12907 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12910 if(this.labelsm > 0){
12911 labelCfg.cls += ' col-sm-' + this.labelsm;
12912 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12915 if(this.labelxs > 0){
12916 labelCfg.cls += ' col-xs-' + this.labelxs;
12917 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12921 } else if ( this.fieldLabel.length) {
12922 // Roo.log(" label");
12926 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12927 tooltip : 'This field is required'
12931 //cls : 'input-group-addon',
12932 html : this.fieldLabel
12937 if(this.indicatorpos == 'right'){
12938 Roo.log('hidden name:'+this.hiddenName);
12942 //cls : 'input-group-addon',
12943 html : this.fieldLabel
12947 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12948 tooltip : 'This field is required'
12957 // Roo.log(" no label && no align");
12964 ['xs','sm','md','lg'].map(function(size){
12965 if (settings[size]) {
12966 cfg.cls += ' col-' + size + '-' + settings[size];
12974 _initEventsCalled : false,
12977 initEvents: function()
12979 if (this._initEventsCalled) { // as we call render... prevent looping...
12982 this._initEventsCalled = true;
12985 throw "can not find store for combo";
12988 this.store = Roo.factory(this.store, Roo.data);
12989 this.store.parent = this;
12991 // if we are building from html. then this element is so complex, that we can not really
12992 // use the rendered HTML.
12993 // so we have to trash and replace the previous code.
12994 if (Roo.XComponent.build_from_html) {
12996 // remove this element....
12997 var e = this.el.dom, k=0;
12998 while (e ) { e = e.previousSibling; ++k;}
13003 this.rendered = false;
13005 this.render(this.parent().getChildContainer(true), k);
13011 if(Roo.isIOS && this.useNativeIOS){
13012 this.initIOSView();
13020 if(Roo.isTouch && this.mobileTouchView){
13021 this.initTouchView();
13026 this.initTickableEvents();
13030 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13032 if(this.hiddenName){
13034 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13036 this.hiddenField.dom.value =
13037 this.hiddenValue !== undefined ? this.hiddenValue :
13038 this.value !== undefined ? this.value : '';
13040 // prevent input submission
13041 this.el.dom.removeAttribute('name');
13042 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13047 // this.el.dom.setAttribute('autocomplete', 'off');
13050 var cls = 'x-combo-list';
13052 //this.list = new Roo.Layer({
13053 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13059 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13060 _this.list.setWidth(lw);
13063 this.list.on('mouseover', this.onViewOver, this);
13064 this.list.on('mousemove', this.onViewMove, this);
13066 this.list.on('scroll', this.onViewScroll, this);
13069 this.list.swallowEvent('mousewheel');
13070 this.assetHeight = 0;
13073 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13074 this.assetHeight += this.header.getHeight();
13077 this.innerList = this.list.createChild({cls:cls+'-inner'});
13078 this.innerList.on('mouseover', this.onViewOver, this);
13079 this.innerList.on('mousemove', this.onViewMove, this);
13080 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13082 if(this.allowBlank && !this.pageSize && !this.disableClear){
13083 this.footer = this.list.createChild({cls:cls+'-ft'});
13084 this.pageTb = new Roo.Toolbar(this.footer);
13088 this.footer = this.list.createChild({cls:cls+'-ft'});
13089 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13090 {pageSize: this.pageSize});
13094 if (this.pageTb && this.allowBlank && !this.disableClear) {
13096 this.pageTb.add(new Roo.Toolbar.Fill(), {
13097 cls: 'x-btn-icon x-btn-clear',
13099 handler: function()
13102 _this.clearValue();
13103 _this.onSelect(false, -1);
13108 this.assetHeight += this.footer.getHeight();
13113 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13116 this.view = new Roo.View(this.list, this.tpl, {
13117 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13119 //this.view.wrapEl.setDisplayed(false);
13120 this.view.on('click', this.onViewClick, this);
13123 this.store.on('beforeload', this.onBeforeLoad, this);
13124 this.store.on('load', this.onLoad, this);
13125 this.store.on('loadexception', this.onLoadException, this);
13127 if(this.resizable){
13128 this.resizer = new Roo.Resizable(this.list, {
13129 pinned:true, handles:'se'
13131 this.resizer.on('resize', function(r, w, h){
13132 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13133 this.listWidth = w;
13134 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13135 this.restrictHeight();
13137 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13140 if(!this.editable){
13141 this.editable = true;
13142 this.setEditable(false);
13147 if (typeof(this.events.add.listeners) != 'undefined') {
13149 this.addicon = this.wrap.createChild(
13150 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13152 this.addicon.on('click', function(e) {
13153 this.fireEvent('add', this);
13156 if (typeof(this.events.edit.listeners) != 'undefined') {
13158 this.editicon = this.wrap.createChild(
13159 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13160 if (this.addicon) {
13161 this.editicon.setStyle('margin-left', '40px');
13163 this.editicon.on('click', function(e) {
13165 // we fire even if inothing is selected..
13166 this.fireEvent('edit', this, this.lastData );
13172 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13173 "up" : function(e){
13174 this.inKeyMode = true;
13178 "down" : function(e){
13179 if(!this.isExpanded()){
13180 this.onTriggerClick();
13182 this.inKeyMode = true;
13187 "enter" : function(e){
13188 // this.onViewClick();
13192 if(this.fireEvent("specialkey", this, e)){
13193 this.onViewClick(false);
13199 "esc" : function(e){
13203 "tab" : function(e){
13206 if(this.fireEvent("specialkey", this, e)){
13207 this.onViewClick(false);
13215 doRelay : function(foo, bar, hname){
13216 if(hname == 'down' || this.scope.isExpanded()){
13217 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13226 this.queryDelay = Math.max(this.queryDelay || 10,
13227 this.mode == 'local' ? 10 : 250);
13230 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13232 if(this.typeAhead){
13233 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13235 if(this.editable !== false){
13236 this.inputEl().on("keyup", this.onKeyUp, this);
13238 if(this.forceSelection){
13239 this.inputEl().on('blur', this.doForce, this);
13243 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13244 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13248 initTickableEvents: function()
13252 if(this.hiddenName){
13254 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13256 this.hiddenField.dom.value =
13257 this.hiddenValue !== undefined ? this.hiddenValue :
13258 this.value !== undefined ? this.value : '';
13260 // prevent input submission
13261 this.el.dom.removeAttribute('name');
13262 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13267 // this.list = this.el.select('ul.dropdown-menu',true).first();
13269 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13270 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13271 if(this.triggerList){
13272 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13275 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13276 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13278 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13279 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13281 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13282 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13284 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13285 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13286 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13289 this.cancelBtn.hide();
13294 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13295 _this.list.setWidth(lw);
13298 this.list.on('mouseover', this.onViewOver, this);
13299 this.list.on('mousemove', this.onViewMove, this);
13301 this.list.on('scroll', this.onViewScroll, this);
13304 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>';
13307 this.view = new Roo.View(this.list, this.tpl, {
13308 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13311 //this.view.wrapEl.setDisplayed(false);
13312 this.view.on('click', this.onViewClick, this);
13316 this.store.on('beforeload', this.onBeforeLoad, this);
13317 this.store.on('load', this.onLoad, this);
13318 this.store.on('loadexception', this.onLoadException, this);
13321 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13322 "up" : function(e){
13323 this.inKeyMode = true;
13327 "down" : function(e){
13328 this.inKeyMode = true;
13332 "enter" : function(e){
13333 if(this.fireEvent("specialkey", this, e)){
13334 this.onViewClick(false);
13340 "esc" : function(e){
13341 this.onTickableFooterButtonClick(e, false, false);
13344 "tab" : function(e){
13345 this.fireEvent("specialkey", this, e);
13347 this.onTickableFooterButtonClick(e, false, false);
13354 doRelay : function(e, fn, key){
13355 if(this.scope.isExpanded()){
13356 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13365 this.queryDelay = Math.max(this.queryDelay || 10,
13366 this.mode == 'local' ? 10 : 250);
13369 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13371 if(this.typeAhead){
13372 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13375 if(this.editable !== false){
13376 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13379 this.indicator = this.indicatorEl();
13381 if(this.indicator){
13382 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13383 this.indicator.hide();
13388 onDestroy : function(){
13390 this.view.setStore(null);
13391 this.view.el.removeAllListeners();
13392 this.view.el.remove();
13393 this.view.purgeListeners();
13396 this.list.dom.innerHTML = '';
13400 this.store.un('beforeload', this.onBeforeLoad, this);
13401 this.store.un('load', this.onLoad, this);
13402 this.store.un('loadexception', this.onLoadException, this);
13404 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13408 fireKey : function(e){
13409 if(e.isNavKeyPress() && !this.list.isVisible()){
13410 this.fireEvent("specialkey", this, e);
13415 onResize: function(w, h){
13416 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13418 // if(typeof w != 'number'){
13419 // // we do not handle it!?!?
13422 // var tw = this.trigger.getWidth();
13423 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13424 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13426 // this.inputEl().setWidth( this.adjustWidth('input', x));
13428 // //this.trigger.setStyle('left', x+'px');
13430 // if(this.list && this.listWidth === undefined){
13431 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13432 // this.list.setWidth(lw);
13433 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13441 * Allow or prevent the user from directly editing the field text. If false is passed,
13442 * the user will only be able to select from the items defined in the dropdown list. This method
13443 * is the runtime equivalent of setting the 'editable' config option at config time.
13444 * @param {Boolean} value True to allow the user to directly edit the field text
13446 setEditable : function(value){
13447 if(value == this.editable){
13450 this.editable = value;
13452 this.inputEl().dom.setAttribute('readOnly', true);
13453 this.inputEl().on('mousedown', this.onTriggerClick, this);
13454 this.inputEl().addClass('x-combo-noedit');
13456 this.inputEl().dom.setAttribute('readOnly', false);
13457 this.inputEl().un('mousedown', this.onTriggerClick, this);
13458 this.inputEl().removeClass('x-combo-noedit');
13464 onBeforeLoad : function(combo,opts){
13465 if(!this.hasFocus){
13469 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13471 this.restrictHeight();
13472 this.selectedIndex = -1;
13476 onLoad : function(){
13478 this.hasQuery = false;
13480 if(!this.hasFocus){
13484 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13485 this.loading.hide();
13488 if(this.store.getCount() > 0){
13491 this.restrictHeight();
13492 if(this.lastQuery == this.allQuery){
13493 if(this.editable && !this.tickable){
13494 this.inputEl().dom.select();
13498 !this.selectByValue(this.value, true) &&
13501 !this.store.lastOptions ||
13502 typeof(this.store.lastOptions.add) == 'undefined' ||
13503 this.store.lastOptions.add != true
13506 this.select(0, true);
13509 if(this.autoFocus){
13512 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13513 this.taTask.delay(this.typeAheadDelay);
13517 this.onEmptyResults();
13523 onLoadException : function()
13525 this.hasQuery = false;
13527 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13528 this.loading.hide();
13531 if(this.tickable && this.editable){
13536 // only causes errors at present
13537 //Roo.log(this.store.reader.jsonData);
13538 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13540 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13546 onTypeAhead : function(){
13547 if(this.store.getCount() > 0){
13548 var r = this.store.getAt(0);
13549 var newValue = r.data[this.displayField];
13550 var len = newValue.length;
13551 var selStart = this.getRawValue().length;
13553 if(selStart != len){
13554 this.setRawValue(newValue);
13555 this.selectText(selStart, newValue.length);
13561 onSelect : function(record, index){
13563 if(this.fireEvent('beforeselect', this, record, index) !== false){
13565 this.setFromData(index > -1 ? record.data : false);
13568 this.fireEvent('select', this, record, index);
13573 * Returns the currently selected field value or empty string if no value is set.
13574 * @return {String} value The selected value
13576 getValue : function()
13578 if(Roo.isIOS && this.useNativeIOS){
13579 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13583 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13586 if(this.valueField){
13587 return typeof this.value != 'undefined' ? this.value : '';
13589 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13593 getRawValue : function()
13595 if(Roo.isIOS && this.useNativeIOS){
13596 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13599 var v = this.inputEl().getValue();
13605 * Clears any text/value currently set in the field
13607 clearValue : function(){
13609 if(this.hiddenField){
13610 this.hiddenField.dom.value = '';
13613 this.setRawValue('');
13614 this.lastSelectionText = '';
13615 this.lastData = false;
13617 var close = this.closeTriggerEl();
13628 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13629 * will be displayed in the field. If the value does not match the data value of an existing item,
13630 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13631 * Otherwise the field will be blank (although the value will still be set).
13632 * @param {String} value The value to match
13634 setValue : function(v)
13636 if(Roo.isIOS && this.useNativeIOS){
13637 this.setIOSValue(v);
13647 if(this.valueField){
13648 var r = this.findRecord(this.valueField, v);
13650 text = r.data[this.displayField];
13651 }else if(this.valueNotFoundText !== undefined){
13652 text = this.valueNotFoundText;
13655 this.lastSelectionText = text;
13656 if(this.hiddenField){
13657 this.hiddenField.dom.value = v;
13659 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13662 var close = this.closeTriggerEl();
13665 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13671 * @property {Object} the last set data for the element
13676 * Sets the value of the field based on a object which is related to the record format for the store.
13677 * @param {Object} value the value to set as. or false on reset?
13679 setFromData : function(o){
13686 var dv = ''; // display value
13687 var vv = ''; // value value..
13689 if (this.displayField) {
13690 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13692 // this is an error condition!!!
13693 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13696 if(this.valueField){
13697 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13700 var close = this.closeTriggerEl();
13703 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13706 if(this.hiddenField){
13707 this.hiddenField.dom.value = vv;
13709 this.lastSelectionText = dv;
13710 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13714 // no hidden field.. - we store the value in 'value', but still display
13715 // display field!!!!
13716 this.lastSelectionText = dv;
13717 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13724 reset : function(){
13725 // overridden so that last data is reset..
13732 this.setValue(this.originalValue);
13733 //this.clearInvalid();
13734 this.lastData = false;
13736 this.view.clearSelections();
13742 findRecord : function(prop, value){
13744 if(this.store.getCount() > 0){
13745 this.store.each(function(r){
13746 if(r.data[prop] == value){
13756 getName: function()
13758 // returns hidden if it's set..
13759 if (!this.rendered) {return ''};
13760 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13764 onViewMove : function(e, t){
13765 this.inKeyMode = false;
13769 onViewOver : function(e, t){
13770 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13773 var item = this.view.findItemFromChild(t);
13776 var index = this.view.indexOf(item);
13777 this.select(index, false);
13782 onViewClick : function(view, doFocus, el, e)
13784 var index = this.view.getSelectedIndexes()[0];
13786 var r = this.store.getAt(index);
13790 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13797 Roo.each(this.tickItems, function(v,k){
13799 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13801 _this.tickItems.splice(k, 1);
13803 if(typeof(e) == 'undefined' && view == false){
13804 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13816 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13817 this.tickItems.push(r.data);
13820 if(typeof(e) == 'undefined' && view == false){
13821 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13828 this.onSelect(r, index);
13830 if(doFocus !== false && !this.blockFocus){
13831 this.inputEl().focus();
13836 restrictHeight : function(){
13837 //this.innerList.dom.style.height = '';
13838 //var inner = this.innerList.dom;
13839 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13840 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13841 //this.list.beginUpdate();
13842 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13843 this.list.alignTo(this.inputEl(), this.listAlign);
13844 this.list.alignTo(this.inputEl(), this.listAlign);
13845 //this.list.endUpdate();
13849 onEmptyResults : function(){
13851 if(this.tickable && this.editable){
13852 this.restrictHeight();
13860 * Returns true if the dropdown list is expanded, else false.
13862 isExpanded : function(){
13863 return this.list.isVisible();
13867 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13868 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13869 * @param {String} value The data value of the item to select
13870 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13871 * selected item if it is not currently in view (defaults to true)
13872 * @return {Boolean} True if the value matched an item in the list, else false
13874 selectByValue : function(v, scrollIntoView){
13875 if(v !== undefined && v !== null){
13876 var r = this.findRecord(this.valueField || this.displayField, v);
13878 this.select(this.store.indexOf(r), scrollIntoView);
13886 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13887 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13888 * @param {Number} index The zero-based index of the list item to select
13889 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13890 * selected item if it is not currently in view (defaults to true)
13892 select : function(index, scrollIntoView){
13893 this.selectedIndex = index;
13894 this.view.select(index);
13895 if(scrollIntoView !== false){
13896 var el = this.view.getNode(index);
13898 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13901 this.list.scrollChildIntoView(el, false);
13907 selectNext : function(){
13908 var ct = this.store.getCount();
13910 if(this.selectedIndex == -1){
13912 }else if(this.selectedIndex < ct-1){
13913 this.select(this.selectedIndex+1);
13919 selectPrev : function(){
13920 var ct = this.store.getCount();
13922 if(this.selectedIndex == -1){
13924 }else if(this.selectedIndex != 0){
13925 this.select(this.selectedIndex-1);
13931 onKeyUp : function(e){
13932 if(this.editable !== false && !e.isSpecialKey()){
13933 this.lastKey = e.getKey();
13934 this.dqTask.delay(this.queryDelay);
13939 validateBlur : function(){
13940 return !this.list || !this.list.isVisible();
13944 initQuery : function(){
13946 var v = this.getRawValue();
13948 if(this.tickable && this.editable){
13949 v = this.tickableInputEl().getValue();
13956 doForce : function(){
13957 if(this.inputEl().dom.value.length > 0){
13958 this.inputEl().dom.value =
13959 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13965 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13966 * query allowing the query action to be canceled if needed.
13967 * @param {String} query The SQL query to execute
13968 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13969 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13970 * saved in the current store (defaults to false)
13972 doQuery : function(q, forceAll){
13974 if(q === undefined || q === null){
13979 forceAll: forceAll,
13983 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13988 forceAll = qe.forceAll;
13989 if(forceAll === true || (q.length >= this.minChars)){
13991 this.hasQuery = true;
13993 if(this.lastQuery != q || this.alwaysQuery){
13994 this.lastQuery = q;
13995 if(this.mode == 'local'){
13996 this.selectedIndex = -1;
13998 this.store.clearFilter();
14001 if(this.specialFilter){
14002 this.fireEvent('specialfilter', this);
14007 this.store.filter(this.displayField, q);
14010 this.store.fireEvent("datachanged", this.store);
14017 this.store.baseParams[this.queryParam] = q;
14019 var options = {params : this.getParams(q)};
14022 options.add = true;
14023 options.params.start = this.page * this.pageSize;
14026 this.store.load(options);
14029 * this code will make the page width larger, at the beginning, the list not align correctly,
14030 * we should expand the list on onLoad
14031 * so command out it
14036 this.selectedIndex = -1;
14041 this.loadNext = false;
14045 getParams : function(q){
14047 //p[this.queryParam] = q;
14051 p.limit = this.pageSize;
14057 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14059 collapse : function(){
14060 if(!this.isExpanded()){
14066 this.hasFocus = false;
14070 this.cancelBtn.hide();
14071 this.trigger.show();
14074 this.tickableInputEl().dom.value = '';
14075 this.tickableInputEl().blur();
14080 Roo.get(document).un('mousedown', this.collapseIf, this);
14081 Roo.get(document).un('mousewheel', this.collapseIf, this);
14082 if (!this.editable) {
14083 Roo.get(document).un('keydown', this.listKeyPress, this);
14085 this.fireEvent('collapse', this);
14091 collapseIf : function(e){
14092 var in_combo = e.within(this.el);
14093 var in_list = e.within(this.list);
14094 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14096 if (in_combo || in_list || is_list) {
14097 //e.stopPropagation();
14102 this.onTickableFooterButtonClick(e, false, false);
14110 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14112 expand : function(){
14114 if(this.isExpanded() || !this.hasFocus){
14118 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14119 this.list.setWidth(lw);
14125 this.restrictHeight();
14129 this.tickItems = Roo.apply([], this.item);
14132 this.cancelBtn.show();
14133 this.trigger.hide();
14136 this.tickableInputEl().focus();
14141 Roo.get(document).on('mousedown', this.collapseIf, this);
14142 Roo.get(document).on('mousewheel', this.collapseIf, this);
14143 if (!this.editable) {
14144 Roo.get(document).on('keydown', this.listKeyPress, this);
14147 this.fireEvent('expand', this);
14151 // Implements the default empty TriggerField.onTriggerClick function
14152 onTriggerClick : function(e)
14154 Roo.log('trigger click');
14156 if(this.disabled || !this.triggerList){
14161 this.loadNext = false;
14163 if(this.isExpanded()){
14165 if (!this.blockFocus) {
14166 this.inputEl().focus();
14170 this.hasFocus = true;
14171 if(this.triggerAction == 'all') {
14172 this.doQuery(this.allQuery, true);
14174 this.doQuery(this.getRawValue());
14176 if (!this.blockFocus) {
14177 this.inputEl().focus();
14182 onTickableTriggerClick : function(e)
14189 this.loadNext = false;
14190 this.hasFocus = true;
14192 if(this.triggerAction == 'all') {
14193 this.doQuery(this.allQuery, true);
14195 this.doQuery(this.getRawValue());
14199 onSearchFieldClick : function(e)
14201 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14202 this.onTickableFooterButtonClick(e, false, false);
14206 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14211 this.loadNext = false;
14212 this.hasFocus = true;
14214 if(this.triggerAction == 'all') {
14215 this.doQuery(this.allQuery, true);
14217 this.doQuery(this.getRawValue());
14221 listKeyPress : function(e)
14223 //Roo.log('listkeypress');
14224 // scroll to first matching element based on key pres..
14225 if (e.isSpecialKey()) {
14228 var k = String.fromCharCode(e.getKey()).toUpperCase();
14231 var csel = this.view.getSelectedNodes();
14232 var cselitem = false;
14234 var ix = this.view.indexOf(csel[0]);
14235 cselitem = this.store.getAt(ix);
14236 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14242 this.store.each(function(v) {
14244 // start at existing selection.
14245 if (cselitem.id == v.id) {
14251 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14252 match = this.store.indexOf(v);
14258 if (match === false) {
14259 return true; // no more action?
14262 this.view.select(match);
14263 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14264 sn.scrollIntoView(sn.dom.parentNode, false);
14267 onViewScroll : function(e, t){
14269 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){
14273 this.hasQuery = true;
14275 this.loading = this.list.select('.loading', true).first();
14277 if(this.loading === null){
14278 this.list.createChild({
14280 cls: 'loading roo-select2-more-results roo-select2-active',
14281 html: 'Loading more results...'
14284 this.loading = this.list.select('.loading', true).first();
14286 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14288 this.loading.hide();
14291 this.loading.show();
14296 this.loadNext = true;
14298 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14303 addItem : function(o)
14305 var dv = ''; // display value
14307 if (this.displayField) {
14308 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14310 // this is an error condition!!!
14311 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14318 var choice = this.choices.createChild({
14320 cls: 'roo-select2-search-choice',
14329 cls: 'roo-select2-search-choice-close fa fa-times',
14334 }, this.searchField);
14336 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14338 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14346 this.inputEl().dom.value = '';
14351 onRemoveItem : function(e, _self, o)
14353 e.preventDefault();
14355 this.lastItem = Roo.apply([], this.item);
14357 var index = this.item.indexOf(o.data) * 1;
14360 Roo.log('not this item?!');
14364 this.item.splice(index, 1);
14369 this.fireEvent('remove', this, e);
14375 syncValue : function()
14377 if(!this.item.length){
14384 Roo.each(this.item, function(i){
14385 if(_this.valueField){
14386 value.push(i[_this.valueField]);
14393 this.value = value.join(',');
14395 if(this.hiddenField){
14396 this.hiddenField.dom.value = this.value;
14399 this.store.fireEvent("datachanged", this.store);
14404 clearItem : function()
14406 if(!this.multiple){
14412 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14420 if(this.tickable && !Roo.isTouch){
14421 this.view.refresh();
14425 inputEl: function ()
14427 if(Roo.isIOS && this.useNativeIOS){
14428 return this.el.select('select.roo-ios-select', true).first();
14431 if(Roo.isTouch && this.mobileTouchView){
14432 return this.el.select('input.form-control',true).first();
14436 return this.searchField;
14439 return this.el.select('input.form-control',true).first();
14442 onTickableFooterButtonClick : function(e, btn, el)
14444 e.preventDefault();
14446 this.lastItem = Roo.apply([], this.item);
14448 if(btn && btn.name == 'cancel'){
14449 this.tickItems = Roo.apply([], this.item);
14458 Roo.each(this.tickItems, function(o){
14466 validate : function()
14468 var v = this.getRawValue();
14471 v = this.getValue();
14474 if(this.disabled || this.allowBlank || v.length){
14479 this.markInvalid();
14483 tickableInputEl : function()
14485 if(!this.tickable || !this.editable){
14486 return this.inputEl();
14489 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14493 getAutoCreateTouchView : function()
14498 cls: 'form-group' //input-group
14504 type : this.inputType,
14505 cls : 'form-control x-combo-noedit',
14506 autocomplete: 'new-password',
14507 placeholder : this.placeholder || '',
14512 input.name = this.name;
14516 input.cls += ' input-' + this.size;
14519 if (this.disabled) {
14520 input.disabled = true;
14531 inputblock.cls += ' input-group';
14533 inputblock.cn.unshift({
14535 cls : 'input-group-addon',
14540 if(this.removable && !this.multiple){
14541 inputblock.cls += ' roo-removable';
14543 inputblock.cn.push({
14546 cls : 'roo-combo-removable-btn close'
14550 if(this.hasFeedback && !this.allowBlank){
14552 inputblock.cls += ' has-feedback';
14554 inputblock.cn.push({
14556 cls: 'glyphicon form-control-feedback'
14563 inputblock.cls += (this.before) ? '' : ' input-group';
14565 inputblock.cn.push({
14567 cls : 'input-group-addon',
14578 cls: 'form-hidden-field'
14592 cls: 'form-hidden-field'
14596 cls: 'roo-select2-choices',
14600 cls: 'roo-select2-search-field',
14613 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14619 if(!this.multiple && this.showToggleBtn){
14626 if (this.caret != false) {
14629 cls: 'fa fa-' + this.caret
14636 cls : 'input-group-addon btn dropdown-toggle',
14641 cls: 'combobox-clear',
14655 combobox.cls += ' roo-select2-container-multi';
14658 var align = this.labelAlign || this.parentLabelAlign();
14660 if (align ==='left' && this.fieldLabel.length) {
14665 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14666 tooltip : 'This field is required'
14670 cls : 'control-label',
14671 html : this.fieldLabel
14682 var labelCfg = cfg.cn[1];
14683 var contentCfg = cfg.cn[2];
14686 if(this.indicatorpos == 'right'){
14690 cls : 'control-label',
14691 html : this.fieldLabel,
14695 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14696 tooltip : 'This field is required'
14709 labelCfg = cfg.cn[0];
14710 contentCfg = cfg.cn[2];
14712 if(this.labelWidth > 12){
14713 labelCfg.style = "width: " + this.labelWidth + 'px';
14716 if(this.labelWidth < 13 && this.labelmd == 0){
14717 this.labelmd = this.labelWidth;
14720 if(this.labellg > 0){
14721 labelCfg.cls += ' col-lg-' + this.labellg;
14722 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14725 if(this.labelmd > 0){
14726 labelCfg.cls += ' col-md-' + this.labelmd;
14727 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14730 if(this.labelsm > 0){
14731 labelCfg.cls += ' col-sm-' + this.labelsm;
14732 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14735 if(this.labelxs > 0){
14736 labelCfg.cls += ' col-xs-' + this.labelxs;
14737 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14741 } else if ( this.fieldLabel.length) {
14745 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14746 tooltip : 'This field is required'
14750 cls : 'control-label',
14751 html : this.fieldLabel
14762 if(this.indicatorpos == 'right'){
14766 cls : 'control-label',
14767 html : this.fieldLabel,
14771 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14772 tooltip : 'This field is required'
14789 var settings = this;
14791 ['xs','sm','md','lg'].map(function(size){
14792 if (settings[size]) {
14793 cfg.cls += ' col-' + size + '-' + settings[size];
14800 initTouchView : function()
14802 this.renderTouchView();
14804 this.touchViewEl.on('scroll', function(){
14805 this.el.dom.scrollTop = 0;
14808 this.originalValue = this.getValue();
14810 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14812 this.inputEl().on("click", this.showTouchView, this);
14813 if (this.triggerEl) {
14814 this.triggerEl.on("click", this.showTouchView, this);
14818 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14819 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14821 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14823 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14824 this.store.on('load', this.onTouchViewLoad, this);
14825 this.store.on('loadexception', this.onTouchViewLoadException, this);
14827 if(this.hiddenName){
14829 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14831 this.hiddenField.dom.value =
14832 this.hiddenValue !== undefined ? this.hiddenValue :
14833 this.value !== undefined ? this.value : '';
14835 this.el.dom.removeAttribute('name');
14836 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14840 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14841 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14844 if(this.removable && !this.multiple){
14845 var close = this.closeTriggerEl();
14847 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14848 close.on('click', this.removeBtnClick, this, close);
14852 * fix the bug in Safari iOS8
14854 this.inputEl().on("focus", function(e){
14855 document.activeElement.blur();
14863 renderTouchView : function()
14865 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14866 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14868 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14869 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14871 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14872 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14873 this.touchViewBodyEl.setStyle('overflow', 'auto');
14875 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14876 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14878 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14879 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14883 showTouchView : function()
14889 this.touchViewHeaderEl.hide();
14891 if(this.modalTitle.length){
14892 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14893 this.touchViewHeaderEl.show();
14896 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14897 this.touchViewEl.show();
14899 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14900 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14901 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14903 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14905 if(this.modalTitle.length){
14906 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14909 this.touchViewBodyEl.setHeight(bodyHeight);
14913 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14915 this.touchViewEl.addClass('in');
14918 this.doTouchViewQuery();
14922 hideTouchView : function()
14924 this.touchViewEl.removeClass('in');
14928 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14930 this.touchViewEl.setStyle('display', 'none');
14935 setTouchViewValue : function()
14942 Roo.each(this.tickItems, function(o){
14947 this.hideTouchView();
14950 doTouchViewQuery : function()
14959 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14963 if(!this.alwaysQuery || this.mode == 'local'){
14964 this.onTouchViewLoad();
14971 onTouchViewBeforeLoad : function(combo,opts)
14977 onTouchViewLoad : function()
14979 if(this.store.getCount() < 1){
14980 this.onTouchViewEmptyResults();
14984 this.clearTouchView();
14986 var rawValue = this.getRawValue();
14988 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14990 this.tickItems = [];
14992 this.store.data.each(function(d, rowIndex){
14993 var row = this.touchViewListGroup.createChild(template);
14995 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14996 row.addClass(d.data.cls);
14999 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15002 html : d.data[this.displayField]
15005 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15006 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15009 row.removeClass('selected');
15010 if(!this.multiple && this.valueField &&
15011 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15014 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15015 row.addClass('selected');
15018 if(this.multiple && this.valueField &&
15019 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15023 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15024 this.tickItems.push(d.data);
15027 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15031 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15033 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15035 if(this.modalTitle.length){
15036 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15039 var listHeight = this.touchViewListGroup.getHeight();
15043 if(firstChecked && listHeight > bodyHeight){
15044 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15049 onTouchViewLoadException : function()
15051 this.hideTouchView();
15054 onTouchViewEmptyResults : function()
15056 this.clearTouchView();
15058 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15060 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15064 clearTouchView : function()
15066 this.touchViewListGroup.dom.innerHTML = '';
15069 onTouchViewClick : function(e, el, o)
15071 e.preventDefault();
15074 var rowIndex = o.rowIndex;
15076 var r = this.store.getAt(rowIndex);
15078 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15080 if(!this.multiple){
15081 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15082 c.dom.removeAttribute('checked');
15085 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15087 this.setFromData(r.data);
15089 var close = this.closeTriggerEl();
15095 this.hideTouchView();
15097 this.fireEvent('select', this, r, rowIndex);
15102 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15103 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15104 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15108 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15109 this.addItem(r.data);
15110 this.tickItems.push(r.data);
15114 getAutoCreateNativeIOS : function()
15117 cls: 'form-group' //input-group,
15122 cls : 'roo-ios-select'
15126 combobox.name = this.name;
15129 if (this.disabled) {
15130 combobox.disabled = true;
15133 var settings = this;
15135 ['xs','sm','md','lg'].map(function(size){
15136 if (settings[size]) {
15137 cfg.cls += ' col-' + size + '-' + settings[size];
15147 initIOSView : function()
15149 this.store.on('load', this.onIOSViewLoad, this);
15154 onIOSViewLoad : function()
15156 if(this.store.getCount() < 1){
15160 this.clearIOSView();
15162 if(this.allowBlank) {
15164 var default_text = '-- SELECT --';
15166 var opt = this.inputEl().createChild({
15169 html : default_text
15173 o[this.valueField] = 0;
15174 o[this.displayField] = default_text;
15176 this.ios_options.push({
15183 this.store.data.each(function(d, rowIndex){
15187 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15188 html = d.data[this.displayField];
15193 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15194 value = d.data[this.valueField];
15203 if(this.value == d.data[this.valueField]){
15204 option['selected'] = true;
15207 var opt = this.inputEl().createChild(option);
15209 this.ios_options.push({
15216 this.inputEl().on('change', function(){
15217 this.fireEvent('select', this);
15222 clearIOSView: function()
15224 this.inputEl().dom.innerHTML = '';
15226 this.ios_options = [];
15229 setIOSValue: function(v)
15233 if(!this.ios_options){
15237 Roo.each(this.ios_options, function(opts){
15239 opts.el.dom.removeAttribute('selected');
15241 if(opts.data[this.valueField] != v){
15245 opts.el.dom.setAttribute('selected', true);
15251 * @cfg {Boolean} grow
15255 * @cfg {Number} growMin
15259 * @cfg {Number} growMax
15268 Roo.apply(Roo.bootstrap.ComboBox, {
15272 cls: 'modal-header',
15294 cls: 'list-group-item',
15298 cls: 'roo-combobox-list-group-item-value'
15302 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15316 listItemCheckbox : {
15318 cls: 'list-group-item',
15322 cls: 'roo-combobox-list-group-item-value'
15326 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15342 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15347 cls: 'modal-footer',
15355 cls: 'col-xs-6 text-left',
15358 cls: 'btn btn-danger roo-touch-view-cancel',
15364 cls: 'col-xs-6 text-right',
15367 cls: 'btn btn-success roo-touch-view-ok',
15378 Roo.apply(Roo.bootstrap.ComboBox, {
15380 touchViewTemplate : {
15382 cls: 'modal fade roo-combobox-touch-view',
15386 cls: 'modal-dialog',
15387 style : 'position:fixed', // we have to fix position....
15391 cls: 'modal-content',
15393 Roo.bootstrap.ComboBox.header,
15394 Roo.bootstrap.ComboBox.body,
15395 Roo.bootstrap.ComboBox.footer
15404 * Ext JS Library 1.1.1
15405 * Copyright(c) 2006-2007, Ext JS, LLC.
15407 * Originally Released Under LGPL - original licence link has changed is not relivant.
15410 * <script type="text/javascript">
15415 * @extends Roo.util.Observable
15416 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15417 * This class also supports single and multi selection modes. <br>
15418 * Create a data model bound view:
15420 var store = new Roo.data.Store(...);
15422 var view = new Roo.View({
15424 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15426 singleSelect: true,
15427 selectedClass: "ydataview-selected",
15431 // listen for node click?
15432 view.on("click", function(vw, index, node, e){
15433 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15437 dataModel.load("foobar.xml");
15439 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15441 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15442 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15444 * Note: old style constructor is still suported (container, template, config)
15447 * Create a new View
15448 * @param {Object} config The config object
15451 Roo.View = function(config, depreciated_tpl, depreciated_config){
15453 this.parent = false;
15455 if (typeof(depreciated_tpl) == 'undefined') {
15456 // new way.. - universal constructor.
15457 Roo.apply(this, config);
15458 this.el = Roo.get(this.el);
15461 this.el = Roo.get(config);
15462 this.tpl = depreciated_tpl;
15463 Roo.apply(this, depreciated_config);
15465 this.wrapEl = this.el.wrap().wrap();
15466 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15469 if(typeof(this.tpl) == "string"){
15470 this.tpl = new Roo.Template(this.tpl);
15472 // support xtype ctors..
15473 this.tpl = new Roo.factory(this.tpl, Roo);
15477 this.tpl.compile();
15482 * @event beforeclick
15483 * Fires before a click is processed. Returns false to cancel the default action.
15484 * @param {Roo.View} this
15485 * @param {Number} index The index of the target node
15486 * @param {HTMLElement} node The target node
15487 * @param {Roo.EventObject} e The raw event object
15489 "beforeclick" : true,
15492 * Fires when a template node is clicked.
15493 * @param {Roo.View} this
15494 * @param {Number} index The index of the target node
15495 * @param {HTMLElement} node The target node
15496 * @param {Roo.EventObject} e The raw event object
15501 * Fires when a template node is double clicked.
15502 * @param {Roo.View} this
15503 * @param {Number} index The index of the target node
15504 * @param {HTMLElement} node The target node
15505 * @param {Roo.EventObject} e The raw event object
15509 * @event contextmenu
15510 * Fires when a template node is right clicked.
15511 * @param {Roo.View} this
15512 * @param {Number} index The index of the target node
15513 * @param {HTMLElement} node The target node
15514 * @param {Roo.EventObject} e The raw event object
15516 "contextmenu" : true,
15518 * @event selectionchange
15519 * Fires when the selected nodes change.
15520 * @param {Roo.View} this
15521 * @param {Array} selections Array of the selected nodes
15523 "selectionchange" : true,
15526 * @event beforeselect
15527 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15528 * @param {Roo.View} this
15529 * @param {HTMLElement} node The node to be selected
15530 * @param {Array} selections Array of currently selected nodes
15532 "beforeselect" : true,
15534 * @event preparedata
15535 * Fires on every row to render, to allow you to change the data.
15536 * @param {Roo.View} this
15537 * @param {Object} data to be rendered (change this)
15539 "preparedata" : true
15547 "click": this.onClick,
15548 "dblclick": this.onDblClick,
15549 "contextmenu": this.onContextMenu,
15553 this.selections = [];
15555 this.cmp = new Roo.CompositeElementLite([]);
15557 this.store = Roo.factory(this.store, Roo.data);
15558 this.setStore(this.store, true);
15561 if ( this.footer && this.footer.xtype) {
15563 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15565 this.footer.dataSource = this.store;
15566 this.footer.container = fctr;
15567 this.footer = Roo.factory(this.footer, Roo);
15568 fctr.insertFirst(this.el);
15570 // this is a bit insane - as the paging toolbar seems to detach the el..
15571 // dom.parentNode.parentNode.parentNode
15572 // they get detached?
15576 Roo.View.superclass.constructor.call(this);
15581 Roo.extend(Roo.View, Roo.util.Observable, {
15584 * @cfg {Roo.data.Store} store Data store to load data from.
15589 * @cfg {String|Roo.Element} el The container element.
15594 * @cfg {String|Roo.Template} tpl The template used by this View
15598 * @cfg {String} dataName the named area of the template to use as the data area
15599 * Works with domtemplates roo-name="name"
15603 * @cfg {String} selectedClass The css class to add to selected nodes
15605 selectedClass : "x-view-selected",
15607 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15612 * @cfg {String} text to display on mask (default Loading)
15616 * @cfg {Boolean} multiSelect Allow multiple selection
15618 multiSelect : false,
15620 * @cfg {Boolean} singleSelect Allow single selection
15622 singleSelect: false,
15625 * @cfg {Boolean} toggleSelect - selecting
15627 toggleSelect : false,
15630 * @cfg {Boolean} tickable - selecting
15635 * Returns the element this view is bound to.
15636 * @return {Roo.Element}
15638 getEl : function(){
15639 return this.wrapEl;
15645 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15647 refresh : function(){
15648 //Roo.log('refresh');
15651 // if we are using something like 'domtemplate', then
15652 // the what gets used is:
15653 // t.applySubtemplate(NAME, data, wrapping data..)
15654 // the outer template then get' applied with
15655 // the store 'extra data'
15656 // and the body get's added to the
15657 // roo-name="data" node?
15658 // <span class='roo-tpl-{name}'></span> ?????
15662 this.clearSelections();
15663 this.el.update("");
15665 var records = this.store.getRange();
15666 if(records.length < 1) {
15668 // is this valid?? = should it render a template??
15670 this.el.update(this.emptyText);
15674 if (this.dataName) {
15675 this.el.update(t.apply(this.store.meta)); //????
15676 el = this.el.child('.roo-tpl-' + this.dataName);
15679 for(var i = 0, len = records.length; i < len; i++){
15680 var data = this.prepareData(records[i].data, i, records[i]);
15681 this.fireEvent("preparedata", this, data, i, records[i]);
15683 var d = Roo.apply({}, data);
15686 Roo.apply(d, {'roo-id' : Roo.id()});
15690 Roo.each(this.parent.item, function(item){
15691 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15694 Roo.apply(d, {'roo-data-checked' : 'checked'});
15698 html[html.length] = Roo.util.Format.trim(
15700 t.applySubtemplate(this.dataName, d, this.store.meta) :
15707 el.update(html.join(""));
15708 this.nodes = el.dom.childNodes;
15709 this.updateIndexes(0);
15714 * Function to override to reformat the data that is sent to
15715 * the template for each node.
15716 * DEPRICATED - use the preparedata event handler.
15717 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15718 * a JSON object for an UpdateManager bound view).
15720 prepareData : function(data, index, record)
15722 this.fireEvent("preparedata", this, data, index, record);
15726 onUpdate : function(ds, record){
15727 // Roo.log('on update');
15728 this.clearSelections();
15729 var index = this.store.indexOf(record);
15730 var n = this.nodes[index];
15731 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15732 n.parentNode.removeChild(n);
15733 this.updateIndexes(index, index);
15739 onAdd : function(ds, records, index)
15741 //Roo.log(['on Add', ds, records, index] );
15742 this.clearSelections();
15743 if(this.nodes.length == 0){
15747 var n = this.nodes[index];
15748 for(var i = 0, len = records.length; i < len; i++){
15749 var d = this.prepareData(records[i].data, i, records[i]);
15751 this.tpl.insertBefore(n, d);
15754 this.tpl.append(this.el, d);
15757 this.updateIndexes(index);
15760 onRemove : function(ds, record, index){
15761 // Roo.log('onRemove');
15762 this.clearSelections();
15763 var el = this.dataName ?
15764 this.el.child('.roo-tpl-' + this.dataName) :
15767 el.dom.removeChild(this.nodes[index]);
15768 this.updateIndexes(index);
15772 * Refresh an individual node.
15773 * @param {Number} index
15775 refreshNode : function(index){
15776 this.onUpdate(this.store, this.store.getAt(index));
15779 updateIndexes : function(startIndex, endIndex){
15780 var ns = this.nodes;
15781 startIndex = startIndex || 0;
15782 endIndex = endIndex || ns.length - 1;
15783 for(var i = startIndex; i <= endIndex; i++){
15784 ns[i].nodeIndex = i;
15789 * Changes the data store this view uses and refresh the view.
15790 * @param {Store} store
15792 setStore : function(store, initial){
15793 if(!initial && this.store){
15794 this.store.un("datachanged", this.refresh);
15795 this.store.un("add", this.onAdd);
15796 this.store.un("remove", this.onRemove);
15797 this.store.un("update", this.onUpdate);
15798 this.store.un("clear", this.refresh);
15799 this.store.un("beforeload", this.onBeforeLoad);
15800 this.store.un("load", this.onLoad);
15801 this.store.un("loadexception", this.onLoad);
15805 store.on("datachanged", this.refresh, this);
15806 store.on("add", this.onAdd, this);
15807 store.on("remove", this.onRemove, this);
15808 store.on("update", this.onUpdate, this);
15809 store.on("clear", this.refresh, this);
15810 store.on("beforeload", this.onBeforeLoad, this);
15811 store.on("load", this.onLoad, this);
15812 store.on("loadexception", this.onLoad, this);
15820 * onbeforeLoad - masks the loading area.
15823 onBeforeLoad : function(store,opts)
15825 //Roo.log('onBeforeLoad');
15827 this.el.update("");
15829 this.el.mask(this.mask ? this.mask : "Loading" );
15831 onLoad : function ()
15838 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15839 * @param {HTMLElement} node
15840 * @return {HTMLElement} The template node
15842 findItemFromChild : function(node){
15843 var el = this.dataName ?
15844 this.el.child('.roo-tpl-' + this.dataName,true) :
15847 if(!node || node.parentNode == el){
15850 var p = node.parentNode;
15851 while(p && p != el){
15852 if(p.parentNode == el){
15861 onClick : function(e){
15862 var item = this.findItemFromChild(e.getTarget());
15864 var index = this.indexOf(item);
15865 if(this.onItemClick(item, index, e) !== false){
15866 this.fireEvent("click", this, index, item, e);
15869 this.clearSelections();
15874 onContextMenu : function(e){
15875 var item = this.findItemFromChild(e.getTarget());
15877 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15882 onDblClick : function(e){
15883 var item = this.findItemFromChild(e.getTarget());
15885 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15889 onItemClick : function(item, index, e)
15891 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15894 if (this.toggleSelect) {
15895 var m = this.isSelected(item) ? 'unselect' : 'select';
15898 _t[m](item, true, false);
15901 if(this.multiSelect || this.singleSelect){
15902 if(this.multiSelect && e.shiftKey && this.lastSelection){
15903 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15905 this.select(item, this.multiSelect && e.ctrlKey);
15906 this.lastSelection = item;
15909 if(!this.tickable){
15910 e.preventDefault();
15918 * Get the number of selected nodes.
15921 getSelectionCount : function(){
15922 return this.selections.length;
15926 * Get the currently selected nodes.
15927 * @return {Array} An array of HTMLElements
15929 getSelectedNodes : function(){
15930 return this.selections;
15934 * Get the indexes of the selected nodes.
15937 getSelectedIndexes : function(){
15938 var indexes = [], s = this.selections;
15939 for(var i = 0, len = s.length; i < len; i++){
15940 indexes.push(s[i].nodeIndex);
15946 * Clear all selections
15947 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15949 clearSelections : function(suppressEvent){
15950 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15951 this.cmp.elements = this.selections;
15952 this.cmp.removeClass(this.selectedClass);
15953 this.selections = [];
15954 if(!suppressEvent){
15955 this.fireEvent("selectionchange", this, this.selections);
15961 * Returns true if the passed node is selected
15962 * @param {HTMLElement/Number} node The node or node index
15963 * @return {Boolean}
15965 isSelected : function(node){
15966 var s = this.selections;
15970 node = this.getNode(node);
15971 return s.indexOf(node) !== -1;
15976 * @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
15977 * @param {Boolean} keepExisting (optional) true to keep existing selections
15978 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15980 select : function(nodeInfo, keepExisting, suppressEvent){
15981 if(nodeInfo instanceof Array){
15983 this.clearSelections(true);
15985 for(var i = 0, len = nodeInfo.length; i < len; i++){
15986 this.select(nodeInfo[i], true, true);
15990 var node = this.getNode(nodeInfo);
15991 if(!node || this.isSelected(node)){
15992 return; // already selected.
15995 this.clearSelections(true);
15998 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15999 Roo.fly(node).addClass(this.selectedClass);
16000 this.selections.push(node);
16001 if(!suppressEvent){
16002 this.fireEvent("selectionchange", this, this.selections);
16010 * @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
16011 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16012 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16014 unselect : function(nodeInfo, keepExisting, suppressEvent)
16016 if(nodeInfo instanceof Array){
16017 Roo.each(this.selections, function(s) {
16018 this.unselect(s, nodeInfo);
16022 var node = this.getNode(nodeInfo);
16023 if(!node || !this.isSelected(node)){
16024 //Roo.log("not selected");
16025 return; // not selected.
16029 Roo.each(this.selections, function(s) {
16031 Roo.fly(node).removeClass(this.selectedClass);
16038 this.selections= ns;
16039 this.fireEvent("selectionchange", this, this.selections);
16043 * Gets a template node.
16044 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16045 * @return {HTMLElement} The node or null if it wasn't found
16047 getNode : function(nodeInfo){
16048 if(typeof nodeInfo == "string"){
16049 return document.getElementById(nodeInfo);
16050 }else if(typeof nodeInfo == "number"){
16051 return this.nodes[nodeInfo];
16057 * Gets a range template nodes.
16058 * @param {Number} startIndex
16059 * @param {Number} endIndex
16060 * @return {Array} An array of nodes
16062 getNodes : function(start, end){
16063 var ns = this.nodes;
16064 start = start || 0;
16065 end = typeof end == "undefined" ? ns.length - 1 : end;
16068 for(var i = start; i <= end; i++){
16072 for(var i = start; i >= end; i--){
16080 * Finds the index of the passed node
16081 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16082 * @return {Number} The index of the node or -1
16084 indexOf : function(node){
16085 node = this.getNode(node);
16086 if(typeof node.nodeIndex == "number"){
16087 return node.nodeIndex;
16089 var ns = this.nodes;
16090 for(var i = 0, len = ns.length; i < len; i++){
16101 * based on jquery fullcalendar
16105 Roo.bootstrap = Roo.bootstrap || {};
16107 * @class Roo.bootstrap.Calendar
16108 * @extends Roo.bootstrap.Component
16109 * Bootstrap Calendar class
16110 * @cfg {Boolean} loadMask (true|false) default false
16111 * @cfg {Object} header generate the user specific header of the calendar, default false
16114 * Create a new Container
16115 * @param {Object} config The config object
16120 Roo.bootstrap.Calendar = function(config){
16121 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16125 * Fires when a date is selected
16126 * @param {DatePicker} this
16127 * @param {Date} date The selected date
16131 * @event monthchange
16132 * Fires when the displayed month changes
16133 * @param {DatePicker} this
16134 * @param {Date} date The selected month
16136 'monthchange': true,
16138 * @event evententer
16139 * Fires when mouse over an event
16140 * @param {Calendar} this
16141 * @param {event} Event
16143 'evententer': true,
16145 * @event eventleave
16146 * Fires when the mouse leaves an
16147 * @param {Calendar} this
16150 'eventleave': true,
16152 * @event eventclick
16153 * Fires when the mouse click an
16154 * @param {Calendar} this
16163 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16166 * @cfg {Number} startDay
16167 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16175 getAutoCreate : function(){
16178 var fc_button = function(name, corner, style, content ) {
16179 return Roo.apply({},{
16181 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16183 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16186 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16197 style : 'width:100%',
16204 cls : 'fc-header-left',
16206 fc_button('prev', 'left', 'arrow', '‹' ),
16207 fc_button('next', 'right', 'arrow', '›' ),
16208 { tag: 'span', cls: 'fc-header-space' },
16209 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16217 cls : 'fc-header-center',
16221 cls: 'fc-header-title',
16224 html : 'month / year'
16232 cls : 'fc-header-right',
16234 /* fc_button('month', 'left', '', 'month' ),
16235 fc_button('week', '', '', 'week' ),
16236 fc_button('day', 'right', '', 'day' )
16248 header = this.header;
16251 var cal_heads = function() {
16253 // fixme - handle this.
16255 for (var i =0; i < Date.dayNames.length; i++) {
16256 var d = Date.dayNames[i];
16259 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16260 html : d.substring(0,3)
16264 ret[0].cls += ' fc-first';
16265 ret[6].cls += ' fc-last';
16268 var cal_cell = function(n) {
16271 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16276 cls: 'fc-day-number',
16280 cls: 'fc-day-content',
16284 style: 'position: relative;' // height: 17px;
16296 var cal_rows = function() {
16299 for (var r = 0; r < 6; r++) {
16306 for (var i =0; i < Date.dayNames.length; i++) {
16307 var d = Date.dayNames[i];
16308 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16311 row.cn[0].cls+=' fc-first';
16312 row.cn[0].cn[0].style = 'min-height:90px';
16313 row.cn[6].cls+=' fc-last';
16317 ret[0].cls += ' fc-first';
16318 ret[4].cls += ' fc-prev-last';
16319 ret[5].cls += ' fc-last';
16326 cls: 'fc-border-separate',
16327 style : 'width:100%',
16335 cls : 'fc-first fc-last',
16353 cls : 'fc-content',
16354 style : "position: relative;",
16357 cls : 'fc-view fc-view-month fc-grid',
16358 style : 'position: relative',
16359 unselectable : 'on',
16362 cls : 'fc-event-container',
16363 style : 'position:absolute;z-index:8;top:0;left:0;'
16381 initEvents : function()
16384 throw "can not find store for calendar";
16390 style: "text-align:center",
16394 style: "background-color:white;width:50%;margin:250 auto",
16398 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16409 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16411 var size = this.el.select('.fc-content', true).first().getSize();
16412 this.maskEl.setSize(size.width, size.height);
16413 this.maskEl.enableDisplayMode("block");
16414 if(!this.loadMask){
16415 this.maskEl.hide();
16418 this.store = Roo.factory(this.store, Roo.data);
16419 this.store.on('load', this.onLoad, this);
16420 this.store.on('beforeload', this.onBeforeLoad, this);
16424 this.cells = this.el.select('.fc-day',true);
16425 //Roo.log(this.cells);
16426 this.textNodes = this.el.query('.fc-day-number');
16427 this.cells.addClassOnOver('fc-state-hover');
16429 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16430 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16431 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16432 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16434 this.on('monthchange', this.onMonthChange, this);
16436 this.update(new Date().clearTime());
16439 resize : function() {
16440 var sz = this.el.getSize();
16442 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16443 this.el.select('.fc-day-content div',true).setHeight(34);
16448 showPrevMonth : function(e){
16449 this.update(this.activeDate.add("mo", -1));
16451 showToday : function(e){
16452 this.update(new Date().clearTime());
16455 showNextMonth : function(e){
16456 this.update(this.activeDate.add("mo", 1));
16460 showPrevYear : function(){
16461 this.update(this.activeDate.add("y", -1));
16465 showNextYear : function(){
16466 this.update(this.activeDate.add("y", 1));
16471 update : function(date)
16473 var vd = this.activeDate;
16474 this.activeDate = date;
16475 // if(vd && this.el){
16476 // var t = date.getTime();
16477 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16478 // Roo.log('using add remove');
16480 // this.fireEvent('monthchange', this, date);
16482 // this.cells.removeClass("fc-state-highlight");
16483 // this.cells.each(function(c){
16484 // if(c.dateValue == t){
16485 // c.addClass("fc-state-highlight");
16486 // setTimeout(function(){
16487 // try{c.dom.firstChild.focus();}catch(e){}
16497 var days = date.getDaysInMonth();
16499 var firstOfMonth = date.getFirstDateOfMonth();
16500 var startingPos = firstOfMonth.getDay()-this.startDay;
16502 if(startingPos < this.startDay){
16506 var pm = date.add(Date.MONTH, -1);
16507 var prevStart = pm.getDaysInMonth()-startingPos;
16509 this.cells = this.el.select('.fc-day',true);
16510 this.textNodes = this.el.query('.fc-day-number');
16511 this.cells.addClassOnOver('fc-state-hover');
16513 var cells = this.cells.elements;
16514 var textEls = this.textNodes;
16516 Roo.each(cells, function(cell){
16517 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16520 days += startingPos;
16522 // convert everything to numbers so it's fast
16523 var day = 86400000;
16524 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16527 //Roo.log(prevStart);
16529 var today = new Date().clearTime().getTime();
16530 var sel = date.clearTime().getTime();
16531 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16532 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16533 var ddMatch = this.disabledDatesRE;
16534 var ddText = this.disabledDatesText;
16535 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16536 var ddaysText = this.disabledDaysText;
16537 var format = this.format;
16539 var setCellClass = function(cal, cell){
16543 //Roo.log('set Cell Class');
16545 var t = d.getTime();
16549 cell.dateValue = t;
16551 cell.className += " fc-today";
16552 cell.className += " fc-state-highlight";
16553 cell.title = cal.todayText;
16556 // disable highlight in other month..
16557 //cell.className += " fc-state-highlight";
16562 cell.className = " fc-state-disabled";
16563 cell.title = cal.minText;
16567 cell.className = " fc-state-disabled";
16568 cell.title = cal.maxText;
16572 if(ddays.indexOf(d.getDay()) != -1){
16573 cell.title = ddaysText;
16574 cell.className = " fc-state-disabled";
16577 if(ddMatch && format){
16578 var fvalue = d.dateFormat(format);
16579 if(ddMatch.test(fvalue)){
16580 cell.title = ddText.replace("%0", fvalue);
16581 cell.className = " fc-state-disabled";
16585 if (!cell.initialClassName) {
16586 cell.initialClassName = cell.dom.className;
16589 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16594 for(; i < startingPos; i++) {
16595 textEls[i].innerHTML = (++prevStart);
16596 d.setDate(d.getDate()+1);
16598 cells[i].className = "fc-past fc-other-month";
16599 setCellClass(this, cells[i]);
16604 for(; i < days; i++){
16605 intDay = i - startingPos + 1;
16606 textEls[i].innerHTML = (intDay);
16607 d.setDate(d.getDate()+1);
16609 cells[i].className = ''; // "x-date-active";
16610 setCellClass(this, cells[i]);
16614 for(; i < 42; i++) {
16615 textEls[i].innerHTML = (++extraDays);
16616 d.setDate(d.getDate()+1);
16618 cells[i].className = "fc-future fc-other-month";
16619 setCellClass(this, cells[i]);
16622 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16624 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16626 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16627 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16629 if(totalRows != 6){
16630 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16631 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16634 this.fireEvent('monthchange', this, date);
16638 if(!this.internalRender){
16639 var main = this.el.dom.firstChild;
16640 var w = main.offsetWidth;
16641 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16642 Roo.fly(main).setWidth(w);
16643 this.internalRender = true;
16644 // opera does not respect the auto grow header center column
16645 // then, after it gets a width opera refuses to recalculate
16646 // without a second pass
16647 if(Roo.isOpera && !this.secondPass){
16648 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16649 this.secondPass = true;
16650 this.update.defer(10, this, [date]);
16657 findCell : function(dt) {
16658 dt = dt.clearTime().getTime();
16660 this.cells.each(function(c){
16661 //Roo.log("check " +c.dateValue + '?=' + dt);
16662 if(c.dateValue == dt){
16672 findCells : function(ev) {
16673 var s = ev.start.clone().clearTime().getTime();
16675 var e= ev.end.clone().clearTime().getTime();
16678 this.cells.each(function(c){
16679 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16681 if(c.dateValue > e){
16684 if(c.dateValue < s){
16693 // findBestRow: function(cells)
16697 // for (var i =0 ; i < cells.length;i++) {
16698 // ret = Math.max(cells[i].rows || 0,ret);
16705 addItem : function(ev)
16707 // look for vertical location slot in
16708 var cells = this.findCells(ev);
16710 // ev.row = this.findBestRow(cells);
16712 // work out the location.
16716 for(var i =0; i < cells.length; i++) {
16718 cells[i].row = cells[0].row;
16721 cells[i].row = cells[i].row + 1;
16731 if (crow.start.getY() == cells[i].getY()) {
16733 crow.end = cells[i];
16750 cells[0].events.push(ev);
16752 this.calevents.push(ev);
16755 clearEvents: function() {
16757 if(!this.calevents){
16761 Roo.each(this.cells.elements, function(c){
16767 Roo.each(this.calevents, function(e) {
16768 Roo.each(e.els, function(el) {
16769 el.un('mouseenter' ,this.onEventEnter, this);
16770 el.un('mouseleave' ,this.onEventLeave, this);
16775 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16781 renderEvents: function()
16785 this.cells.each(function(c) {
16794 if(c.row != c.events.length){
16795 r = 4 - (4 - (c.row - c.events.length));
16798 c.events = ev.slice(0, r);
16799 c.more = ev.slice(r);
16801 if(c.more.length && c.more.length == 1){
16802 c.events.push(c.more.pop());
16805 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16809 this.cells.each(function(c) {
16811 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16814 for (var e = 0; e < c.events.length; e++){
16815 var ev = c.events[e];
16816 var rows = ev.rows;
16818 for(var i = 0; i < rows.length; i++) {
16820 // how many rows should it span..
16823 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16824 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16826 unselectable : "on",
16829 cls: 'fc-event-inner',
16833 // cls: 'fc-event-time',
16834 // html : cells.length > 1 ? '' : ev.time
16838 cls: 'fc-event-title',
16839 html : String.format('{0}', ev.title)
16846 cls: 'ui-resizable-handle ui-resizable-e',
16847 html : '  '
16854 cfg.cls += ' fc-event-start';
16856 if ((i+1) == rows.length) {
16857 cfg.cls += ' fc-event-end';
16860 var ctr = _this.el.select('.fc-event-container',true).first();
16861 var cg = ctr.createChild(cfg);
16863 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16864 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16866 var r = (c.more.length) ? 1 : 0;
16867 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16868 cg.setWidth(ebox.right - sbox.x -2);
16870 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16871 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16872 cg.on('click', _this.onEventClick, _this, ev);
16883 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16884 style : 'position: absolute',
16885 unselectable : "on",
16888 cls: 'fc-event-inner',
16892 cls: 'fc-event-title',
16900 cls: 'ui-resizable-handle ui-resizable-e',
16901 html : '  '
16907 var ctr = _this.el.select('.fc-event-container',true).first();
16908 var cg = ctr.createChild(cfg);
16910 var sbox = c.select('.fc-day-content',true).first().getBox();
16911 var ebox = c.select('.fc-day-content',true).first().getBox();
16913 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16914 cg.setWidth(ebox.right - sbox.x -2);
16916 cg.on('click', _this.onMoreEventClick, _this, c.more);
16926 onEventEnter: function (e, el,event,d) {
16927 this.fireEvent('evententer', this, el, event);
16930 onEventLeave: function (e, el,event,d) {
16931 this.fireEvent('eventleave', this, el, event);
16934 onEventClick: function (e, el,event,d) {
16935 this.fireEvent('eventclick', this, el, event);
16938 onMonthChange: function () {
16942 onMoreEventClick: function(e, el, more)
16946 this.calpopover.placement = 'right';
16947 this.calpopover.setTitle('More');
16949 this.calpopover.setContent('');
16951 var ctr = this.calpopover.el.select('.popover-content', true).first();
16953 Roo.each(more, function(m){
16955 cls : 'fc-event-hori fc-event-draggable',
16958 var cg = ctr.createChild(cfg);
16960 cg.on('click', _this.onEventClick, _this, m);
16963 this.calpopover.show(el);
16968 onLoad: function ()
16970 this.calevents = [];
16973 if(this.store.getCount() > 0){
16974 this.store.data.each(function(d){
16977 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16978 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16979 time : d.data.start_time,
16980 title : d.data.title,
16981 description : d.data.description,
16982 venue : d.data.venue
16987 this.renderEvents();
16989 if(this.calevents.length && this.loadMask){
16990 this.maskEl.hide();
16994 onBeforeLoad: function()
16996 this.clearEvents();
16998 this.maskEl.show();
17012 * @class Roo.bootstrap.Popover
17013 * @extends Roo.bootstrap.Component
17014 * Bootstrap Popover class
17015 * @cfg {String} html contents of the popover (or false to use children..)
17016 * @cfg {String} title of popover (or false to hide)
17017 * @cfg {String} placement how it is placed
17018 * @cfg {String} trigger click || hover (or false to trigger manually)
17019 * @cfg {String} over what (parent or false to trigger manually.)
17020 * @cfg {Number} delay - delay before showing
17023 * Create a new Popover
17024 * @param {Object} config The config object
17027 Roo.bootstrap.Popover = function(config){
17028 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17034 * After the popover show
17036 * @param {Roo.bootstrap.Popover} this
17041 * After the popover hide
17043 * @param {Roo.bootstrap.Popover} this
17049 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17051 title: 'Fill in a title',
17054 placement : 'right',
17055 trigger : 'hover', // hover
17061 can_build_overlaid : false,
17063 getChildContainer : function()
17065 return this.el.select('.popover-content',true).first();
17068 getAutoCreate : function(){
17071 cls : 'popover roo-dynamic',
17072 style: 'display:block',
17078 cls : 'popover-inner',
17082 cls: 'popover-title',
17086 cls : 'popover-content',
17097 setTitle: function(str)
17100 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17102 setContent: function(str)
17105 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17107 // as it get's added to the bottom of the page.
17108 onRender : function(ct, position)
17110 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17112 var cfg = Roo.apply({}, this.getAutoCreate());
17116 cfg.cls += ' ' + this.cls;
17119 cfg.style = this.style;
17121 //Roo.log("adding to ");
17122 this.el = Roo.get(document.body).createChild(cfg, position);
17123 // Roo.log(this.el);
17128 initEvents : function()
17130 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17131 this.el.enableDisplayMode('block');
17133 if (this.over === false) {
17136 if (this.triggers === false) {
17139 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17140 var triggers = this.trigger ? this.trigger.split(' ') : [];
17141 Roo.each(triggers, function(trigger) {
17143 if (trigger == 'click') {
17144 on_el.on('click', this.toggle, this);
17145 } else if (trigger != 'manual') {
17146 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17147 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17149 on_el.on(eventIn ,this.enter, this);
17150 on_el.on(eventOut, this.leave, this);
17161 toggle : function () {
17162 this.hoverState == 'in' ? this.leave() : this.enter();
17165 enter : function () {
17167 clearTimeout(this.timeout);
17169 this.hoverState = 'in';
17171 if (!this.delay || !this.delay.show) {
17176 this.timeout = setTimeout(function () {
17177 if (_t.hoverState == 'in') {
17180 }, this.delay.show)
17183 leave : function() {
17184 clearTimeout(this.timeout);
17186 this.hoverState = 'out';
17188 if (!this.delay || !this.delay.hide) {
17193 this.timeout = setTimeout(function () {
17194 if (_t.hoverState == 'out') {
17197 }, this.delay.hide)
17200 show : function (on_el)
17203 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17207 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17208 if (this.html !== false) {
17209 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17211 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17212 if (!this.title.length) {
17213 this.el.select('.popover-title',true).hide();
17216 var placement = typeof this.placement == 'function' ?
17217 this.placement.call(this, this.el, on_el) :
17220 var autoToken = /\s?auto?\s?/i;
17221 var autoPlace = autoToken.test(placement);
17223 placement = placement.replace(autoToken, '') || 'top';
17227 //this.el.setXY([0,0]);
17229 this.el.dom.style.display='block';
17230 this.el.addClass(placement);
17232 //this.el.appendTo(on_el);
17234 var p = this.getPosition();
17235 var box = this.el.getBox();
17240 var align = Roo.bootstrap.Popover.alignment[placement];
17241 this.el.alignTo(on_el, align[0],align[1]);
17242 //var arrow = this.el.select('.arrow',true).first();
17243 //arrow.set(align[2],
17245 this.el.addClass('in');
17248 if (this.el.hasClass('fade')) {
17252 this.hoverState = 'in';
17254 this.fireEvent('show', this);
17259 this.el.setXY([0,0]);
17260 this.el.removeClass('in');
17262 this.hoverState = null;
17264 this.fireEvent('hide', this);
17269 Roo.bootstrap.Popover.alignment = {
17270 'left' : ['r-l', [-10,0], 'right'],
17271 'right' : ['l-r', [10,0], 'left'],
17272 'bottom' : ['t-b', [0,10], 'top'],
17273 'top' : [ 'b-t', [0,-10], 'bottom']
17284 * @class Roo.bootstrap.Progress
17285 * @extends Roo.bootstrap.Component
17286 * Bootstrap Progress class
17287 * @cfg {Boolean} striped striped of the progress bar
17288 * @cfg {Boolean} active animated of the progress bar
17292 * Create a new Progress
17293 * @param {Object} config The config object
17296 Roo.bootstrap.Progress = function(config){
17297 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17300 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17305 getAutoCreate : function(){
17313 cfg.cls += ' progress-striped';
17317 cfg.cls += ' active';
17336 * @class Roo.bootstrap.ProgressBar
17337 * @extends Roo.bootstrap.Component
17338 * Bootstrap ProgressBar class
17339 * @cfg {Number} aria_valuenow aria-value now
17340 * @cfg {Number} aria_valuemin aria-value min
17341 * @cfg {Number} aria_valuemax aria-value max
17342 * @cfg {String} label label for the progress bar
17343 * @cfg {String} panel (success | info | warning | danger )
17344 * @cfg {String} role role of the progress bar
17345 * @cfg {String} sr_only text
17349 * Create a new ProgressBar
17350 * @param {Object} config The config object
17353 Roo.bootstrap.ProgressBar = function(config){
17354 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17357 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17361 aria_valuemax : 100,
17367 getAutoCreate : function()
17372 cls: 'progress-bar',
17373 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17385 cfg.role = this.role;
17388 if(this.aria_valuenow){
17389 cfg['aria-valuenow'] = this.aria_valuenow;
17392 if(this.aria_valuemin){
17393 cfg['aria-valuemin'] = this.aria_valuemin;
17396 if(this.aria_valuemax){
17397 cfg['aria-valuemax'] = this.aria_valuemax;
17400 if(this.label && !this.sr_only){
17401 cfg.html = this.label;
17405 cfg.cls += ' progress-bar-' + this.panel;
17411 update : function(aria_valuenow)
17413 this.aria_valuenow = aria_valuenow;
17415 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17430 * @class Roo.bootstrap.TabGroup
17431 * @extends Roo.bootstrap.Column
17432 * Bootstrap Column class
17433 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17434 * @cfg {Boolean} carousel true to make the group behave like a carousel
17435 * @cfg {Boolean} bullets show bullets for the panels
17436 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17437 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17438 * @cfg {Boolean} showarrow (true|false) show arrow default true
17441 * Create a new TabGroup
17442 * @param {Object} config The config object
17445 Roo.bootstrap.TabGroup = function(config){
17446 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17448 this.navId = Roo.id();
17451 Roo.bootstrap.TabGroup.register(this);
17455 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17458 transition : false,
17463 slideOnTouch : false,
17466 getAutoCreate : function()
17468 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17470 cfg.cls += ' tab-content';
17472 if (this.carousel) {
17473 cfg.cls += ' carousel slide';
17476 cls : 'carousel-inner',
17480 if(this.bullets && !Roo.isTouch){
17483 cls : 'carousel-bullets',
17487 if(this.bullets_cls){
17488 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17495 cfg.cn[0].cn.push(bullets);
17498 if(this.showarrow){
17499 cfg.cn[0].cn.push({
17501 class : 'carousel-arrow',
17505 class : 'carousel-prev',
17509 class : 'fa fa-chevron-left'
17515 class : 'carousel-next',
17519 class : 'fa fa-chevron-right'
17532 initEvents: function()
17534 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17535 // this.el.on("touchstart", this.onTouchStart, this);
17538 if(this.autoslide){
17541 this.slideFn = window.setInterval(function() {
17542 _this.showPanelNext();
17546 if(this.showarrow){
17547 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17548 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17554 // onTouchStart : function(e, el, o)
17556 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17560 // this.showPanelNext();
17564 getChildContainer : function()
17566 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17570 * register a Navigation item
17571 * @param {Roo.bootstrap.NavItem} the navitem to add
17573 register : function(item)
17575 this.tabs.push( item);
17576 item.navId = this.navId; // not really needed..
17581 getActivePanel : function()
17584 Roo.each(this.tabs, function(t) {
17594 getPanelByName : function(n)
17597 Roo.each(this.tabs, function(t) {
17598 if (t.tabId == n) {
17606 indexOfPanel : function(p)
17609 Roo.each(this.tabs, function(t,i) {
17610 if (t.tabId == p.tabId) {
17619 * show a specific panel
17620 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17621 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17623 showPanel : function (pan)
17625 if(this.transition || typeof(pan) == 'undefined'){
17626 Roo.log("waiting for the transitionend");
17630 if (typeof(pan) == 'number') {
17631 pan = this.tabs[pan];
17634 if (typeof(pan) == 'string') {
17635 pan = this.getPanelByName(pan);
17638 var cur = this.getActivePanel();
17641 Roo.log('pan or acitve pan is undefined');
17645 if (pan.tabId == this.getActivePanel().tabId) {
17649 if (false === cur.fireEvent('beforedeactivate')) {
17653 if(this.bullets > 0 && !Roo.isTouch){
17654 this.setActiveBullet(this.indexOfPanel(pan));
17657 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17659 this.transition = true;
17660 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17661 var lr = dir == 'next' ? 'left' : 'right';
17662 pan.el.addClass(dir); // or prev
17663 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17664 cur.el.addClass(lr); // or right
17665 pan.el.addClass(lr);
17668 cur.el.on('transitionend', function() {
17669 Roo.log("trans end?");
17671 pan.el.removeClass([lr,dir]);
17672 pan.setActive(true);
17674 cur.el.removeClass([lr]);
17675 cur.setActive(false);
17677 _this.transition = false;
17679 }, this, { single: true } );
17684 cur.setActive(false);
17685 pan.setActive(true);
17690 showPanelNext : function()
17692 var i = this.indexOfPanel(this.getActivePanel());
17694 if (i >= this.tabs.length - 1 && !this.autoslide) {
17698 if (i >= this.tabs.length - 1 && this.autoslide) {
17702 this.showPanel(this.tabs[i+1]);
17705 showPanelPrev : function()
17707 var i = this.indexOfPanel(this.getActivePanel());
17709 if (i < 1 && !this.autoslide) {
17713 if (i < 1 && this.autoslide) {
17714 i = this.tabs.length;
17717 this.showPanel(this.tabs[i-1]);
17721 addBullet: function()
17723 if(!this.bullets || Roo.isTouch){
17726 var ctr = this.el.select('.carousel-bullets',true).first();
17727 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17728 var bullet = ctr.createChild({
17729 cls : 'bullet bullet-' + i
17730 },ctr.dom.lastChild);
17735 bullet.on('click', (function(e, el, o, ii, t){
17737 e.preventDefault();
17739 this.showPanel(ii);
17741 if(this.autoslide && this.slideFn){
17742 clearInterval(this.slideFn);
17743 this.slideFn = window.setInterval(function() {
17744 _this.showPanelNext();
17748 }).createDelegate(this, [i, bullet], true));
17753 setActiveBullet : function(i)
17759 Roo.each(this.el.select('.bullet', true).elements, function(el){
17760 el.removeClass('selected');
17763 var bullet = this.el.select('.bullet-' + i, true).first();
17769 bullet.addClass('selected');
17780 Roo.apply(Roo.bootstrap.TabGroup, {
17784 * register a Navigation Group
17785 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17787 register : function(navgrp)
17789 this.groups[navgrp.navId] = navgrp;
17793 * fetch a Navigation Group based on the navigation ID
17794 * if one does not exist , it will get created.
17795 * @param {string} the navgroup to add
17796 * @returns {Roo.bootstrap.NavGroup} the navgroup
17798 get: function(navId) {
17799 if (typeof(this.groups[navId]) == 'undefined') {
17800 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17802 return this.groups[navId] ;
17817 * @class Roo.bootstrap.TabPanel
17818 * @extends Roo.bootstrap.Component
17819 * Bootstrap TabPanel class
17820 * @cfg {Boolean} active panel active
17821 * @cfg {String} html panel content
17822 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17823 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17824 * @cfg {String} href click to link..
17828 * Create a new TabPanel
17829 * @param {Object} config The config object
17832 Roo.bootstrap.TabPanel = function(config){
17833 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17837 * Fires when the active status changes
17838 * @param {Roo.bootstrap.TabPanel} this
17839 * @param {Boolean} state the new state
17844 * @event beforedeactivate
17845 * Fires before a tab is de-activated - can be used to do validation on a form.
17846 * @param {Roo.bootstrap.TabPanel} this
17847 * @return {Boolean} false if there is an error
17850 'beforedeactivate': true
17853 this.tabId = this.tabId || Roo.id();
17857 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17865 getAutoCreate : function(){
17868 // item is needed for carousel - not sure if it has any effect otherwise
17869 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17870 html: this.html || ''
17874 cfg.cls += ' active';
17878 cfg.tabId = this.tabId;
17885 initEvents: function()
17887 var p = this.parent();
17889 this.navId = this.navId || p.navId;
17891 if (typeof(this.navId) != 'undefined') {
17892 // not really needed.. but just in case.. parent should be a NavGroup.
17893 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17897 var i = tg.tabs.length - 1;
17899 if(this.active && tg.bullets > 0 && i < tg.bullets){
17900 tg.setActiveBullet(i);
17904 this.el.on('click', this.onClick, this);
17907 this.el.on("touchstart", this.onTouchStart, this);
17908 this.el.on("touchmove", this.onTouchMove, this);
17909 this.el.on("touchend", this.onTouchEnd, this);
17914 onRender : function(ct, position)
17916 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17919 setActive : function(state)
17921 Roo.log("panel - set active " + this.tabId + "=" + state);
17923 this.active = state;
17925 this.el.removeClass('active');
17927 } else if (!this.el.hasClass('active')) {
17928 this.el.addClass('active');
17931 this.fireEvent('changed', this, state);
17934 onClick : function(e)
17936 e.preventDefault();
17938 if(!this.href.length){
17942 window.location.href = this.href;
17951 onTouchStart : function(e)
17953 this.swiping = false;
17955 this.startX = e.browserEvent.touches[0].clientX;
17956 this.startY = e.browserEvent.touches[0].clientY;
17959 onTouchMove : function(e)
17961 this.swiping = true;
17963 this.endX = e.browserEvent.touches[0].clientX;
17964 this.endY = e.browserEvent.touches[0].clientY;
17967 onTouchEnd : function(e)
17974 var tabGroup = this.parent();
17976 if(this.endX > this.startX){ // swiping right
17977 tabGroup.showPanelPrev();
17981 if(this.startX > this.endX){ // swiping left
17982 tabGroup.showPanelNext();
18001 * @class Roo.bootstrap.DateField
18002 * @extends Roo.bootstrap.Input
18003 * Bootstrap DateField class
18004 * @cfg {Number} weekStart default 0
18005 * @cfg {String} viewMode default empty, (months|years)
18006 * @cfg {String} minViewMode default empty, (months|years)
18007 * @cfg {Number} startDate default -Infinity
18008 * @cfg {Number} endDate default Infinity
18009 * @cfg {Boolean} todayHighlight default false
18010 * @cfg {Boolean} todayBtn default false
18011 * @cfg {Boolean} calendarWeeks default false
18012 * @cfg {Object} daysOfWeekDisabled default empty
18013 * @cfg {Boolean} singleMode default false (true | false)
18015 * @cfg {Boolean} keyboardNavigation default true
18016 * @cfg {String} language default en
18019 * Create a new DateField
18020 * @param {Object} config The config object
18023 Roo.bootstrap.DateField = function(config){
18024 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18028 * Fires when this field show.
18029 * @param {Roo.bootstrap.DateField} this
18030 * @param {Mixed} date The date value
18035 * Fires when this field hide.
18036 * @param {Roo.bootstrap.DateField} this
18037 * @param {Mixed} date The date value
18042 * Fires when select a date.
18043 * @param {Roo.bootstrap.DateField} this
18044 * @param {Mixed} date The date value
18048 * @event beforeselect
18049 * Fires when before select a date.
18050 * @param {Roo.bootstrap.DateField} this
18051 * @param {Mixed} date The date value
18053 beforeselect : true
18057 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18060 * @cfg {String} format
18061 * The default date format string which can be overriden for localization support. The format must be
18062 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18066 * @cfg {String} altFormats
18067 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18068 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18070 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18078 todayHighlight : false,
18084 keyboardNavigation: true,
18086 calendarWeeks: false,
18088 startDate: -Infinity,
18092 daysOfWeekDisabled: [],
18096 singleMode : false,
18098 UTCDate: function()
18100 return new Date(Date.UTC.apply(Date, arguments));
18103 UTCToday: function()
18105 var today = new Date();
18106 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18109 getDate: function() {
18110 var d = this.getUTCDate();
18111 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18114 getUTCDate: function() {
18118 setDate: function(d) {
18119 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18122 setUTCDate: function(d) {
18124 this.setValue(this.formatDate(this.date));
18127 onRender: function(ct, position)
18130 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18132 this.language = this.language || 'en';
18133 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18134 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18136 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18137 this.format = this.format || 'm/d/y';
18138 this.isInline = false;
18139 this.isInput = true;
18140 this.component = this.el.select('.add-on', true).first() || false;
18141 this.component = (this.component && this.component.length === 0) ? false : this.component;
18142 this.hasInput = this.component && this.inputEl().length;
18144 if (typeof(this.minViewMode === 'string')) {
18145 switch (this.minViewMode) {
18147 this.minViewMode = 1;
18150 this.minViewMode = 2;
18153 this.minViewMode = 0;
18158 if (typeof(this.viewMode === 'string')) {
18159 switch (this.viewMode) {
18172 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18174 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18176 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18178 this.picker().on('mousedown', this.onMousedown, this);
18179 this.picker().on('click', this.onClick, this);
18181 this.picker().addClass('datepicker-dropdown');
18183 this.startViewMode = this.viewMode;
18185 if(this.singleMode){
18186 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18187 v.setVisibilityMode(Roo.Element.DISPLAY);
18191 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18192 v.setStyle('width', '189px');
18196 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18197 if(!this.calendarWeeks){
18202 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18203 v.attr('colspan', function(i, val){
18204 return parseInt(val) + 1;
18209 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18211 this.setStartDate(this.startDate);
18212 this.setEndDate(this.endDate);
18214 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18221 if(this.isInline) {
18226 picker : function()
18228 return this.pickerEl;
18229 // return this.el.select('.datepicker', true).first();
18232 fillDow: function()
18234 var dowCnt = this.weekStart;
18243 if(this.calendarWeeks){
18251 while (dowCnt < this.weekStart + 7) {
18255 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18259 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18262 fillMonths: function()
18265 var months = this.picker().select('>.datepicker-months td', true).first();
18267 months.dom.innerHTML = '';
18273 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18276 months.createChild(month);
18283 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;
18285 if (this.date < this.startDate) {
18286 this.viewDate = new Date(this.startDate);
18287 } else if (this.date > this.endDate) {
18288 this.viewDate = new Date(this.endDate);
18290 this.viewDate = new Date(this.date);
18298 var d = new Date(this.viewDate),
18299 year = d.getUTCFullYear(),
18300 month = d.getUTCMonth(),
18301 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18302 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18303 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18304 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18305 currentDate = this.date && this.date.valueOf(),
18306 today = this.UTCToday();
18308 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18310 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18312 // this.picker.select('>tfoot th.today').
18313 // .text(dates[this.language].today)
18314 // .toggle(this.todayBtn !== false);
18316 this.updateNavArrows();
18319 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18321 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18323 prevMonth.setUTCDate(day);
18325 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18327 var nextMonth = new Date(prevMonth);
18329 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18331 nextMonth = nextMonth.valueOf();
18333 var fillMonths = false;
18335 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18337 while(prevMonth.valueOf() < nextMonth) {
18340 if (prevMonth.getUTCDay() === this.weekStart) {
18342 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18350 if(this.calendarWeeks){
18351 // ISO 8601: First week contains first thursday.
18352 // ISO also states week starts on Monday, but we can be more abstract here.
18354 // Start of current week: based on weekstart/current date
18355 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18356 // Thursday of this week
18357 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18358 // First Thursday of year, year from thursday
18359 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18360 // Calendar week: ms between thursdays, div ms per day, div 7 days
18361 calWeek = (th - yth) / 864e5 / 7 + 1;
18363 fillMonths.cn.push({
18371 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18373 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18376 if (this.todayHighlight &&
18377 prevMonth.getUTCFullYear() == today.getFullYear() &&
18378 prevMonth.getUTCMonth() == today.getMonth() &&
18379 prevMonth.getUTCDate() == today.getDate()) {
18380 clsName += ' today';
18383 if (currentDate && prevMonth.valueOf() === currentDate) {
18384 clsName += ' active';
18387 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18388 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18389 clsName += ' disabled';
18392 fillMonths.cn.push({
18394 cls: 'day ' + clsName,
18395 html: prevMonth.getDate()
18398 prevMonth.setDate(prevMonth.getDate()+1);
18401 var currentYear = this.date && this.date.getUTCFullYear();
18402 var currentMonth = this.date && this.date.getUTCMonth();
18404 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18406 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18407 v.removeClass('active');
18409 if(currentYear === year && k === currentMonth){
18410 v.addClass('active');
18413 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18414 v.addClass('disabled');
18420 year = parseInt(year/10, 10) * 10;
18422 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18424 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18427 for (var i = -1; i < 11; i++) {
18428 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18430 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18438 showMode: function(dir)
18441 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18444 Roo.each(this.picker().select('>div',true).elements, function(v){
18445 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18448 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18453 if(this.isInline) {
18457 this.picker().removeClass(['bottom', 'top']);
18459 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18461 * place to the top of element!
18465 this.picker().addClass('top');
18466 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18471 this.picker().addClass('bottom');
18473 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18476 parseDate : function(value)
18478 if(!value || value instanceof Date){
18481 var v = Date.parseDate(value, this.format);
18482 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18483 v = Date.parseDate(value, 'Y-m-d');
18485 if(!v && this.altFormats){
18486 if(!this.altFormatsArray){
18487 this.altFormatsArray = this.altFormats.split("|");
18489 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18490 v = Date.parseDate(value, this.altFormatsArray[i]);
18496 formatDate : function(date, fmt)
18498 return (!date || !(date instanceof Date)) ?
18499 date : date.dateFormat(fmt || this.format);
18502 onFocus : function()
18504 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18508 onBlur : function()
18510 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18512 var d = this.inputEl().getValue();
18521 this.picker().show();
18525 this.fireEvent('show', this, this.date);
18530 if(this.isInline) {
18533 this.picker().hide();
18534 this.viewMode = this.startViewMode;
18537 this.fireEvent('hide', this, this.date);
18541 onMousedown: function(e)
18543 e.stopPropagation();
18544 e.preventDefault();
18549 Roo.bootstrap.DateField.superclass.keyup.call(this);
18553 setValue: function(v)
18555 if(this.fireEvent('beforeselect', this, v) !== false){
18556 var d = new Date(this.parseDate(v) ).clearTime();
18558 if(isNaN(d.getTime())){
18559 this.date = this.viewDate = '';
18560 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18564 v = this.formatDate(d);
18566 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18568 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18572 this.fireEvent('select', this, this.date);
18576 getValue: function()
18578 return this.formatDate(this.date);
18581 fireKey: function(e)
18583 if (!this.picker().isVisible()){
18584 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18590 var dateChanged = false,
18592 newDate, newViewDate;
18597 e.preventDefault();
18601 if (!this.keyboardNavigation) {
18604 dir = e.keyCode == 37 ? -1 : 1;
18607 newDate = this.moveYear(this.date, dir);
18608 newViewDate = this.moveYear(this.viewDate, dir);
18609 } else if (e.shiftKey){
18610 newDate = this.moveMonth(this.date, dir);
18611 newViewDate = this.moveMonth(this.viewDate, dir);
18613 newDate = new Date(this.date);
18614 newDate.setUTCDate(this.date.getUTCDate() + dir);
18615 newViewDate = new Date(this.viewDate);
18616 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18618 if (this.dateWithinRange(newDate)){
18619 this.date = newDate;
18620 this.viewDate = newViewDate;
18621 this.setValue(this.formatDate(this.date));
18623 e.preventDefault();
18624 dateChanged = true;
18629 if (!this.keyboardNavigation) {
18632 dir = e.keyCode == 38 ? -1 : 1;
18634 newDate = this.moveYear(this.date, dir);
18635 newViewDate = this.moveYear(this.viewDate, dir);
18636 } else if (e.shiftKey){
18637 newDate = this.moveMonth(this.date, dir);
18638 newViewDate = this.moveMonth(this.viewDate, dir);
18640 newDate = new Date(this.date);
18641 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18642 newViewDate = new Date(this.viewDate);
18643 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18645 if (this.dateWithinRange(newDate)){
18646 this.date = newDate;
18647 this.viewDate = newViewDate;
18648 this.setValue(this.formatDate(this.date));
18650 e.preventDefault();
18651 dateChanged = true;
18655 this.setValue(this.formatDate(this.date));
18657 e.preventDefault();
18660 this.setValue(this.formatDate(this.date));
18674 onClick: function(e)
18676 e.stopPropagation();
18677 e.preventDefault();
18679 var target = e.getTarget();
18681 if(target.nodeName.toLowerCase() === 'i'){
18682 target = Roo.get(target).dom.parentNode;
18685 var nodeName = target.nodeName;
18686 var className = target.className;
18687 var html = target.innerHTML;
18688 //Roo.log(nodeName);
18690 switch(nodeName.toLowerCase()) {
18692 switch(className) {
18698 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18699 switch(this.viewMode){
18701 this.viewDate = this.moveMonth(this.viewDate, dir);
18705 this.viewDate = this.moveYear(this.viewDate, dir);
18711 var date = new Date();
18712 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18714 this.setValue(this.formatDate(this.date));
18721 if (className.indexOf('disabled') < 0) {
18722 this.viewDate.setUTCDate(1);
18723 if (className.indexOf('month') > -1) {
18724 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18726 var year = parseInt(html, 10) || 0;
18727 this.viewDate.setUTCFullYear(year);
18731 if(this.singleMode){
18732 this.setValue(this.formatDate(this.viewDate));
18743 //Roo.log(className);
18744 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18745 var day = parseInt(html, 10) || 1;
18746 var year = this.viewDate.getUTCFullYear(),
18747 month = this.viewDate.getUTCMonth();
18749 if (className.indexOf('old') > -1) {
18756 } else if (className.indexOf('new') > -1) {
18764 //Roo.log([year,month,day]);
18765 this.date = this.UTCDate(year, month, day,0,0,0,0);
18766 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18768 //Roo.log(this.formatDate(this.date));
18769 this.setValue(this.formatDate(this.date));
18776 setStartDate: function(startDate)
18778 this.startDate = startDate || -Infinity;
18779 if (this.startDate !== -Infinity) {
18780 this.startDate = this.parseDate(this.startDate);
18783 this.updateNavArrows();
18786 setEndDate: function(endDate)
18788 this.endDate = endDate || Infinity;
18789 if (this.endDate !== Infinity) {
18790 this.endDate = this.parseDate(this.endDate);
18793 this.updateNavArrows();
18796 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18798 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18799 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18800 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18802 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18803 return parseInt(d, 10);
18806 this.updateNavArrows();
18809 updateNavArrows: function()
18811 if(this.singleMode){
18815 var d = new Date(this.viewDate),
18816 year = d.getUTCFullYear(),
18817 month = d.getUTCMonth();
18819 Roo.each(this.picker().select('.prev', true).elements, function(v){
18821 switch (this.viewMode) {
18824 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18830 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18837 Roo.each(this.picker().select('.next', true).elements, function(v){
18839 switch (this.viewMode) {
18842 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18848 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18856 moveMonth: function(date, dir)
18861 var new_date = new Date(date.valueOf()),
18862 day = new_date.getUTCDate(),
18863 month = new_date.getUTCMonth(),
18864 mag = Math.abs(dir),
18866 dir = dir > 0 ? 1 : -1;
18869 // If going back one month, make sure month is not current month
18870 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18872 return new_date.getUTCMonth() == month;
18874 // If going forward one month, make sure month is as expected
18875 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18877 return new_date.getUTCMonth() != new_month;
18879 new_month = month + dir;
18880 new_date.setUTCMonth(new_month);
18881 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18882 if (new_month < 0 || new_month > 11) {
18883 new_month = (new_month + 12) % 12;
18886 // For magnitudes >1, move one month at a time...
18887 for (var i=0; i<mag; i++) {
18888 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18889 new_date = this.moveMonth(new_date, dir);
18891 // ...then reset the day, keeping it in the new month
18892 new_month = new_date.getUTCMonth();
18893 new_date.setUTCDate(day);
18895 return new_month != new_date.getUTCMonth();
18898 // Common date-resetting loop -- if date is beyond end of month, make it
18901 new_date.setUTCDate(--day);
18902 new_date.setUTCMonth(new_month);
18907 moveYear: function(date, dir)
18909 return this.moveMonth(date, dir*12);
18912 dateWithinRange: function(date)
18914 return date >= this.startDate && date <= this.endDate;
18920 this.picker().remove();
18923 validateValue : function(value)
18925 if(value.length < 1) {
18926 if(this.allowBlank){
18932 if(value.length < this.minLength){
18935 if(value.length > this.maxLength){
18939 var vt = Roo.form.VTypes;
18940 if(!vt[this.vtype](value, this)){
18944 if(typeof this.validator == "function"){
18945 var msg = this.validator(value);
18951 if(this.regex && !this.regex.test(value)){
18955 if(typeof(this.parseDate(value)) == 'undefined'){
18959 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18963 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18973 Roo.apply(Roo.bootstrap.DateField, {
18984 html: '<i class="fa fa-arrow-left"/>'
18994 html: '<i class="fa fa-arrow-right"/>'
19036 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19037 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19038 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19039 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19040 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19053 navFnc: 'FullYear',
19058 navFnc: 'FullYear',
19063 Roo.apply(Roo.bootstrap.DateField, {
19067 cls: 'datepicker dropdown-menu roo-dynamic',
19071 cls: 'datepicker-days',
19075 cls: 'table-condensed',
19077 Roo.bootstrap.DateField.head,
19081 Roo.bootstrap.DateField.footer
19088 cls: 'datepicker-months',
19092 cls: 'table-condensed',
19094 Roo.bootstrap.DateField.head,
19095 Roo.bootstrap.DateField.content,
19096 Roo.bootstrap.DateField.footer
19103 cls: 'datepicker-years',
19107 cls: 'table-condensed',
19109 Roo.bootstrap.DateField.head,
19110 Roo.bootstrap.DateField.content,
19111 Roo.bootstrap.DateField.footer
19130 * @class Roo.bootstrap.TimeField
19131 * @extends Roo.bootstrap.Input
19132 * Bootstrap DateField class
19136 * Create a new TimeField
19137 * @param {Object} config The config object
19140 Roo.bootstrap.TimeField = function(config){
19141 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19145 * Fires when this field show.
19146 * @param {Roo.bootstrap.DateField} thisthis
19147 * @param {Mixed} date The date value
19152 * Fires when this field hide.
19153 * @param {Roo.bootstrap.DateField} this
19154 * @param {Mixed} date The date value
19159 * Fires when select a date.
19160 * @param {Roo.bootstrap.DateField} this
19161 * @param {Mixed} date The date value
19167 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19170 * @cfg {String} format
19171 * The default time format string which can be overriden for localization support. The format must be
19172 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19176 onRender: function(ct, position)
19179 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19181 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19183 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19185 this.pop = this.picker().select('>.datepicker-time',true).first();
19186 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19188 this.picker().on('mousedown', this.onMousedown, this);
19189 this.picker().on('click', this.onClick, this);
19191 this.picker().addClass('datepicker-dropdown');
19196 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19197 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19198 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19199 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19200 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19201 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19205 fireKey: function(e){
19206 if (!this.picker().isVisible()){
19207 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19213 e.preventDefault();
19221 this.onTogglePeriod();
19224 this.onIncrementMinutes();
19227 this.onDecrementMinutes();
19236 onClick: function(e) {
19237 e.stopPropagation();
19238 e.preventDefault();
19241 picker : function()
19243 return this.el.select('.datepicker', true).first();
19246 fillTime: function()
19248 var time = this.pop.select('tbody', true).first();
19250 time.dom.innerHTML = '';
19265 cls: 'hours-up glyphicon glyphicon-chevron-up'
19285 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19306 cls: 'timepicker-hour',
19321 cls: 'timepicker-minute',
19336 cls: 'btn btn-primary period',
19358 cls: 'hours-down glyphicon glyphicon-chevron-down'
19378 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19396 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19403 var hours = this.time.getHours();
19404 var minutes = this.time.getMinutes();
19417 hours = hours - 12;
19421 hours = '0' + hours;
19425 minutes = '0' + minutes;
19428 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19429 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19430 this.pop.select('button', true).first().dom.innerHTML = period;
19436 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19438 var cls = ['bottom'];
19440 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19447 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19452 this.picker().addClass(cls.join('-'));
19456 Roo.each(cls, function(c){
19458 _this.picker().setTop(_this.inputEl().getHeight());
19462 _this.picker().setTop(0 - _this.picker().getHeight());
19467 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19471 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19478 onFocus : function()
19480 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19484 onBlur : function()
19486 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19492 this.picker().show();
19497 this.fireEvent('show', this, this.date);
19502 this.picker().hide();
19505 this.fireEvent('hide', this, this.date);
19508 setTime : function()
19511 this.setValue(this.time.format(this.format));
19513 this.fireEvent('select', this, this.date);
19518 onMousedown: function(e){
19519 e.stopPropagation();
19520 e.preventDefault();
19523 onIncrementHours: function()
19525 Roo.log('onIncrementHours');
19526 this.time = this.time.add(Date.HOUR, 1);
19531 onDecrementHours: function()
19533 Roo.log('onDecrementHours');
19534 this.time = this.time.add(Date.HOUR, -1);
19538 onIncrementMinutes: function()
19540 Roo.log('onIncrementMinutes');
19541 this.time = this.time.add(Date.MINUTE, 1);
19545 onDecrementMinutes: function()
19547 Roo.log('onDecrementMinutes');
19548 this.time = this.time.add(Date.MINUTE, -1);
19552 onTogglePeriod: function()
19554 Roo.log('onTogglePeriod');
19555 this.time = this.time.add(Date.HOUR, 12);
19562 Roo.apply(Roo.bootstrap.TimeField, {
19592 cls: 'btn btn-info ok',
19604 Roo.apply(Roo.bootstrap.TimeField, {
19608 cls: 'datepicker dropdown-menu',
19612 cls: 'datepicker-time',
19616 cls: 'table-condensed',
19618 Roo.bootstrap.TimeField.content,
19619 Roo.bootstrap.TimeField.footer
19638 * @class Roo.bootstrap.MonthField
19639 * @extends Roo.bootstrap.Input
19640 * Bootstrap MonthField class
19642 * @cfg {String} language default en
19645 * Create a new MonthField
19646 * @param {Object} config The config object
19649 Roo.bootstrap.MonthField = function(config){
19650 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19655 * Fires when this field show.
19656 * @param {Roo.bootstrap.MonthField} this
19657 * @param {Mixed} date The date value
19662 * Fires when this field hide.
19663 * @param {Roo.bootstrap.MonthField} this
19664 * @param {Mixed} date The date value
19669 * Fires when select a date.
19670 * @param {Roo.bootstrap.MonthField} this
19671 * @param {String} oldvalue The old value
19672 * @param {String} newvalue The new value
19678 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19680 onRender: function(ct, position)
19683 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19685 this.language = this.language || 'en';
19686 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19687 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19689 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19690 this.isInline = false;
19691 this.isInput = true;
19692 this.component = this.el.select('.add-on', true).first() || false;
19693 this.component = (this.component && this.component.length === 0) ? false : this.component;
19694 this.hasInput = this.component && this.inputEL().length;
19696 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19698 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19700 this.picker().on('mousedown', this.onMousedown, this);
19701 this.picker().on('click', this.onClick, this);
19703 this.picker().addClass('datepicker-dropdown');
19705 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19706 v.setStyle('width', '189px');
19713 if(this.isInline) {
19719 setValue: function(v, suppressEvent)
19721 var o = this.getValue();
19723 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19727 if(suppressEvent !== true){
19728 this.fireEvent('select', this, o, v);
19733 getValue: function()
19738 onClick: function(e)
19740 e.stopPropagation();
19741 e.preventDefault();
19743 var target = e.getTarget();
19745 if(target.nodeName.toLowerCase() === 'i'){
19746 target = Roo.get(target).dom.parentNode;
19749 var nodeName = target.nodeName;
19750 var className = target.className;
19751 var html = target.innerHTML;
19753 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19757 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19759 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19765 picker : function()
19767 return this.pickerEl;
19770 fillMonths: function()
19773 var months = this.picker().select('>.datepicker-months td', true).first();
19775 months.dom.innerHTML = '';
19781 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19784 months.createChild(month);
19793 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19794 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19797 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19798 e.removeClass('active');
19800 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19801 e.addClass('active');
19808 if(this.isInline) {
19812 this.picker().removeClass(['bottom', 'top']);
19814 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19816 * place to the top of element!
19820 this.picker().addClass('top');
19821 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19826 this.picker().addClass('bottom');
19828 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19831 onFocus : function()
19833 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19837 onBlur : function()
19839 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19841 var d = this.inputEl().getValue();
19850 this.picker().show();
19851 this.picker().select('>.datepicker-months', true).first().show();
19855 this.fireEvent('show', this, this.date);
19860 if(this.isInline) {
19863 this.picker().hide();
19864 this.fireEvent('hide', this, this.date);
19868 onMousedown: function(e)
19870 e.stopPropagation();
19871 e.preventDefault();
19876 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19880 fireKey: function(e)
19882 if (!this.picker().isVisible()){
19883 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19894 e.preventDefault();
19898 dir = e.keyCode == 37 ? -1 : 1;
19900 this.vIndex = this.vIndex + dir;
19902 if(this.vIndex < 0){
19906 if(this.vIndex > 11){
19910 if(isNaN(this.vIndex)){
19914 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19920 dir = e.keyCode == 38 ? -1 : 1;
19922 this.vIndex = this.vIndex + dir * 4;
19924 if(this.vIndex < 0){
19928 if(this.vIndex > 11){
19932 if(isNaN(this.vIndex)){
19936 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19941 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19942 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19946 e.preventDefault();
19949 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19950 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19966 this.picker().remove();
19971 Roo.apply(Roo.bootstrap.MonthField, {
19990 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19991 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19996 Roo.apply(Roo.bootstrap.MonthField, {
20000 cls: 'datepicker dropdown-menu roo-dynamic',
20004 cls: 'datepicker-months',
20008 cls: 'table-condensed',
20010 Roo.bootstrap.DateField.content
20030 * @class Roo.bootstrap.CheckBox
20031 * @extends Roo.bootstrap.Input
20032 * Bootstrap CheckBox class
20034 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20035 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20036 * @cfg {String} boxLabel The text that appears beside the checkbox
20037 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20038 * @cfg {Boolean} checked initnal the element
20039 * @cfg {Boolean} inline inline the element (default false)
20040 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20043 * Create a new CheckBox
20044 * @param {Object} config The config object
20047 Roo.bootstrap.CheckBox = function(config){
20048 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20053 * Fires when the element is checked or unchecked.
20054 * @param {Roo.bootstrap.CheckBox} this This input
20055 * @param {Boolean} checked The new checked value
20062 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20064 inputType: 'checkbox',
20072 getAutoCreate : function()
20074 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20080 cfg.cls = 'form-group ' + this.inputType; //input-group
20083 cfg.cls += ' ' + this.inputType + '-inline';
20089 type : this.inputType,
20090 value : this.inputValue,
20091 cls : 'roo-' + this.inputType, //'form-box',
20092 placeholder : this.placeholder || ''
20096 if(this.inputType != 'radio'){
20100 cls : 'roo-hidden-value',
20101 value : this.checked ? this.valueOff : this.inputValue
20106 if (this.weight) { // Validity check?
20107 cfg.cls += " " + this.inputType + "-" + this.weight;
20110 if (this.disabled) {
20111 input.disabled=true;
20115 input.checked = this.checked;
20122 input.name = this.name;
20124 if(this.inputType != 'radio'){
20125 hidden.name = this.name;
20126 input.name = '_hidden_' + this.name;
20131 input.cls += ' input-' + this.size;
20136 ['xs','sm','md','lg'].map(function(size){
20137 if (settings[size]) {
20138 cfg.cls += ' col-' + size + '-' + settings[size];
20142 var inputblock = input;
20144 if (this.before || this.after) {
20147 cls : 'input-group',
20152 inputblock.cn.push({
20154 cls : 'input-group-addon',
20159 inputblock.cn.push(input);
20161 if(this.inputType != 'radio'){
20162 inputblock.cn.push(hidden);
20166 inputblock.cn.push({
20168 cls : 'input-group-addon',
20175 if (align ==='left' && this.fieldLabel.length) {
20176 // Roo.log("left and has label");
20181 cls : 'control-label',
20182 html : this.fieldLabel
20193 if(this.labelWidth > 12){
20194 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20197 if(this.labelWidth < 13 && this.labelmd == 0){
20198 this.labelmd = this.labelWidth;
20201 if(this.labellg > 0){
20202 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20203 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20206 if(this.labelmd > 0){
20207 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20208 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20211 if(this.labelsm > 0){
20212 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20213 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20216 if(this.labelxs > 0){
20217 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20218 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20221 } else if ( this.fieldLabel.length) {
20222 // Roo.log(" label");
20226 tag: this.boxLabel ? 'span' : 'label',
20228 cls: 'control-label box-input-label',
20229 //cls : 'input-group-addon',
20230 html : this.fieldLabel
20240 // Roo.log(" no label && no align");
20241 cfg.cn = [ inputblock ] ;
20247 var boxLabelCfg = {
20249 //'for': id, // box label is handled by onclick - so no for...
20251 html: this.boxLabel
20255 boxLabelCfg.tooltip = this.tooltip;
20258 cfg.cn.push(boxLabelCfg);
20261 if(this.inputType != 'radio'){
20262 cfg.cn.push(hidden);
20270 * return the real input element.
20272 inputEl: function ()
20274 return this.el.select('input.roo-' + this.inputType,true).first();
20276 hiddenEl: function ()
20278 return this.el.select('input.roo-hidden-value',true).first();
20281 labelEl: function()
20283 return this.el.select('label.control-label',true).first();
20285 /* depricated... */
20289 return this.labelEl();
20292 boxLabelEl: function()
20294 return this.el.select('label.box-label',true).first();
20297 initEvents : function()
20299 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20301 this.inputEl().on('click', this.onClick, this);
20303 if (this.boxLabel) {
20304 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20307 this.startValue = this.getValue();
20310 Roo.bootstrap.CheckBox.register(this);
20314 onClick : function()
20316 this.setChecked(!this.checked);
20319 setChecked : function(state,suppressEvent)
20321 this.startValue = this.getValue();
20323 if(this.inputType == 'radio'){
20325 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20326 e.dom.checked = false;
20329 this.inputEl().dom.checked = true;
20331 this.inputEl().dom.value = this.inputValue;
20333 if(suppressEvent !== true){
20334 this.fireEvent('check', this, true);
20342 this.checked = state;
20344 this.inputEl().dom.checked = state;
20347 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20349 if(suppressEvent !== true){
20350 this.fireEvent('check', this, state);
20356 getValue : function()
20358 if(this.inputType == 'radio'){
20359 return this.getGroupValue();
20362 return this.hiddenEl().dom.value;
20366 getGroupValue : function()
20368 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20372 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20375 setValue : function(v,suppressEvent)
20377 if(this.inputType == 'radio'){
20378 this.setGroupValue(v, suppressEvent);
20382 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20387 setGroupValue : function(v, suppressEvent)
20389 this.startValue = this.getValue();
20391 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20392 e.dom.checked = false;
20394 if(e.dom.value == v){
20395 e.dom.checked = true;
20399 if(suppressEvent !== true){
20400 this.fireEvent('check', this, true);
20408 validate : function()
20412 (this.inputType == 'radio' && this.validateRadio()) ||
20413 (this.inputType == 'checkbox' && this.validateCheckbox())
20419 this.markInvalid();
20423 validateRadio : function()
20425 if(this.allowBlank){
20431 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20432 if(!e.dom.checked){
20444 validateCheckbox : function()
20447 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20448 //return (this.getValue() == this.inputValue) ? true : false;
20451 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20459 for(var i in group){
20464 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20471 * Mark this field as valid
20473 markValid : function()
20477 this.fireEvent('valid', this);
20479 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20482 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20489 if(this.inputType == 'radio'){
20490 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20491 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20492 e.findParent('.form-group', false, true).addClass(_this.validClass);
20499 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20500 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20504 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20510 for(var i in group){
20511 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20512 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20517 * Mark this field as invalid
20518 * @param {String} msg The validation message
20520 markInvalid : function(msg)
20522 if(this.allowBlank){
20528 this.fireEvent('invalid', this, msg);
20530 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20533 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20537 label.markInvalid();
20540 if(this.inputType == 'radio'){
20541 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20542 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20543 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20550 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20551 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20555 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20561 for(var i in group){
20562 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20563 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20568 clearInvalid : function()
20570 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20572 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20574 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20577 label.iconEl.removeClass(label.validClass);
20578 label.iconEl.removeClass(label.invalidClass);
20582 disable : function()
20584 if(this.inputType != 'radio'){
20585 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20592 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20593 _this.getActionEl().addClass(this.disabledClass);
20594 e.dom.disabled = true;
20598 this.disabled = true;
20599 this.fireEvent("disable", this);
20603 enable : function()
20605 if(this.inputType != 'radio'){
20606 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20613 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20614 _this.getActionEl().removeClass(this.disabledClass);
20615 e.dom.disabled = false;
20619 this.disabled = false;
20620 this.fireEvent("enable", this);
20626 Roo.apply(Roo.bootstrap.CheckBox, {
20631 * register a CheckBox Group
20632 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20634 register : function(checkbox)
20636 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20637 this.groups[checkbox.groupId] = {};
20640 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20644 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20648 * fetch a CheckBox Group based on the group ID
20649 * @param {string} the group ID
20650 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20652 get: function(groupId) {
20653 if (typeof(this.groups[groupId]) == 'undefined') {
20657 return this.groups[groupId] ;
20670 * @class Roo.bootstrap.Radio
20671 * @extends Roo.bootstrap.Component
20672 * Bootstrap Radio class
20673 * @cfg {String} boxLabel - the label associated
20674 * @cfg {String} value - the value of radio
20677 * Create a new Radio
20678 * @param {Object} config The config object
20680 Roo.bootstrap.Radio = function(config){
20681 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20685 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20691 getAutoCreate : function()
20695 cls : 'form-group radio',
20700 html : this.boxLabel
20708 initEvents : function()
20710 this.parent().register(this);
20712 this.el.on('click', this.onClick, this);
20716 onClick : function()
20718 this.setChecked(true);
20721 setChecked : function(state, suppressEvent)
20723 this.parent().setValue(this.value, suppressEvent);
20738 * @class Roo.bootstrap.SecurePass
20739 * @extends Roo.bootstrap.Input
20740 * Bootstrap SecurePass class
20744 * Create a new SecurePass
20745 * @param {Object} config The config object
20748 Roo.bootstrap.SecurePass = function (config) {
20749 // these go here, so the translation tool can replace them..
20751 PwdEmpty: "Please type a password, and then retype it to confirm.",
20752 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20753 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20754 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20755 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20756 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20757 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20758 TooWeak: "Your password is Too Weak."
20760 this.meterLabel = "Password strength:";
20761 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20762 this.meterClass = [
20763 "roo-password-meter-tooweak",
20764 "roo-password-meter-weak",
20765 "roo-password-meter-medium",
20766 "roo-password-meter-strong",
20767 "roo-password-meter-grey"
20772 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20775 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20777 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20779 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20780 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20781 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20782 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20783 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20784 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20785 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20795 * @cfg {String/Object} Label for the strength meter (defaults to
20796 * 'Password strength:')
20801 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20802 * ['Weak', 'Medium', 'Strong'])
20805 pwdStrengths: false,
20818 initEvents: function ()
20820 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20822 if (this.el.is('input[type=password]') && Roo.isSafari) {
20823 this.el.on('keydown', this.SafariOnKeyDown, this);
20826 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20829 onRender: function (ct, position)
20831 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20832 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20833 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20835 this.trigger.createChild({
20840 cls: 'roo-password-meter-grey col-xs-12',
20843 //width: this.meterWidth + 'px'
20847 cls: 'roo-password-meter-text'
20853 if (this.hideTrigger) {
20854 this.trigger.setDisplayed(false);
20856 this.setSize(this.width || '', this.height || '');
20859 onDestroy: function ()
20861 if (this.trigger) {
20862 this.trigger.removeAllListeners();
20863 this.trigger.remove();
20866 this.wrap.remove();
20868 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20871 checkStrength: function ()
20873 var pwd = this.inputEl().getValue();
20874 if (pwd == this._lastPwd) {
20879 if (this.ClientSideStrongPassword(pwd)) {
20881 } else if (this.ClientSideMediumPassword(pwd)) {
20883 } else if (this.ClientSideWeakPassword(pwd)) {
20889 Roo.log('strength1: ' + strength);
20891 //var pm = this.trigger.child('div/div/div').dom;
20892 var pm = this.trigger.child('div/div');
20893 pm.removeClass(this.meterClass);
20894 pm.addClass(this.meterClass[strength]);
20897 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20899 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20901 this._lastPwd = pwd;
20905 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20907 this._lastPwd = '';
20909 var pm = this.trigger.child('div/div');
20910 pm.removeClass(this.meterClass);
20911 pm.addClass('roo-password-meter-grey');
20914 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20917 this.inputEl().dom.type='password';
20920 validateValue: function (value)
20923 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20926 if (value.length == 0) {
20927 if (this.allowBlank) {
20928 this.clearInvalid();
20932 this.markInvalid(this.errors.PwdEmpty);
20933 this.errorMsg = this.errors.PwdEmpty;
20941 if ('[\x21-\x7e]*'.match(value)) {
20942 this.markInvalid(this.errors.PwdBadChar);
20943 this.errorMsg = this.errors.PwdBadChar;
20946 if (value.length < 6) {
20947 this.markInvalid(this.errors.PwdShort);
20948 this.errorMsg = this.errors.PwdShort;
20951 if (value.length > 16) {
20952 this.markInvalid(this.errors.PwdLong);
20953 this.errorMsg = this.errors.PwdLong;
20957 if (this.ClientSideStrongPassword(value)) {
20959 } else if (this.ClientSideMediumPassword(value)) {
20961 } else if (this.ClientSideWeakPassword(value)) {
20968 if (strength < 2) {
20969 //this.markInvalid(this.errors.TooWeak);
20970 this.errorMsg = this.errors.TooWeak;
20975 console.log('strength2: ' + strength);
20977 //var pm = this.trigger.child('div/div/div').dom;
20979 var pm = this.trigger.child('div/div');
20980 pm.removeClass(this.meterClass);
20981 pm.addClass(this.meterClass[strength]);
20983 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20985 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20987 this.errorMsg = '';
20991 CharacterSetChecks: function (type)
20994 this.fResult = false;
20997 isctype: function (character, type)
21000 case this.kCapitalLetter:
21001 if (character >= 'A' && character <= 'Z') {
21006 case this.kSmallLetter:
21007 if (character >= 'a' && character <= 'z') {
21013 if (character >= '0' && character <= '9') {
21018 case this.kPunctuation:
21019 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21030 IsLongEnough: function (pwd, size)
21032 return !(pwd == null || isNaN(size) || pwd.length < size);
21035 SpansEnoughCharacterSets: function (word, nb)
21037 if (!this.IsLongEnough(word, nb))
21042 var characterSetChecks = new Array(
21043 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21044 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21047 for (var index = 0; index < word.length; ++index) {
21048 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21049 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21050 characterSetChecks[nCharSet].fResult = true;
21057 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21058 if (characterSetChecks[nCharSet].fResult) {
21063 if (nCharSets < nb) {
21069 ClientSideStrongPassword: function (pwd)
21071 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21074 ClientSideMediumPassword: function (pwd)
21076 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21079 ClientSideWeakPassword: function (pwd)
21081 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21084 })//<script type="text/javascript">
21087 * Based Ext JS Library 1.1.1
21088 * Copyright(c) 2006-2007, Ext JS, LLC.
21094 * @class Roo.HtmlEditorCore
21095 * @extends Roo.Component
21096 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21098 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21101 Roo.HtmlEditorCore = function(config){
21104 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21109 * @event initialize
21110 * Fires when the editor is fully initialized (including the iframe)
21111 * @param {Roo.HtmlEditorCore} this
21116 * Fires when the editor is first receives the focus. Any insertion must wait
21117 * until after this event.
21118 * @param {Roo.HtmlEditorCore} this
21122 * @event beforesync
21123 * Fires before the textarea is updated with content from the editor iframe. Return false
21124 * to cancel the sync.
21125 * @param {Roo.HtmlEditorCore} this
21126 * @param {String} html
21130 * @event beforepush
21131 * Fires before the iframe editor is updated with content from the textarea. Return false
21132 * to cancel the push.
21133 * @param {Roo.HtmlEditorCore} this
21134 * @param {String} html
21139 * Fires when the textarea is updated with content from the editor iframe.
21140 * @param {Roo.HtmlEditorCore} this
21141 * @param {String} html
21146 * Fires when the iframe editor is updated with content from the textarea.
21147 * @param {Roo.HtmlEditorCore} this
21148 * @param {String} html
21153 * @event editorevent
21154 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21155 * @param {Roo.HtmlEditorCore} this
21161 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21163 // defaults : white / black...
21164 this.applyBlacklists();
21171 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21175 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21181 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21186 * @cfg {Number} height (in pixels)
21190 * @cfg {Number} width (in pixels)
21195 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21198 stylesheets: false,
21203 // private properties
21204 validationEvent : false,
21206 initialized : false,
21208 sourceEditMode : false,
21209 onFocus : Roo.emptyFn,
21211 hideMode:'offsets',
21215 // blacklist + whitelisted elements..
21222 * Protected method that will not generally be called directly. It
21223 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21224 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21226 getDocMarkup : function(){
21230 // inherit styels from page...??
21231 if (this.stylesheets === false) {
21233 Roo.get(document.head).select('style').each(function(node) {
21234 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21237 Roo.get(document.head).select('link').each(function(node) {
21238 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21241 } else if (!this.stylesheets.length) {
21243 st = '<style type="text/css">' +
21244 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21250 st += '<style type="text/css">' +
21251 'IMG { cursor: pointer } ' +
21255 return '<html><head>' + st +
21256 //<style type="text/css">' +
21257 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21259 ' </head><body class="roo-htmleditor-body"></body></html>';
21263 onRender : function(ct, position)
21266 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21267 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21270 this.el.dom.style.border = '0 none';
21271 this.el.dom.setAttribute('tabIndex', -1);
21272 this.el.addClass('x-hidden hide');
21276 if(Roo.isIE){ // fix IE 1px bogus margin
21277 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21281 this.frameId = Roo.id();
21285 var iframe = this.owner.wrap.createChild({
21287 cls: 'form-control', // bootstrap..
21289 name: this.frameId,
21290 frameBorder : 'no',
21291 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21296 this.iframe = iframe.dom;
21298 this.assignDocWin();
21300 this.doc.designMode = 'on';
21303 this.doc.write(this.getDocMarkup());
21307 var task = { // must defer to wait for browser to be ready
21309 //console.log("run task?" + this.doc.readyState);
21310 this.assignDocWin();
21311 if(this.doc.body || this.doc.readyState == 'complete'){
21313 this.doc.designMode="on";
21317 Roo.TaskMgr.stop(task);
21318 this.initEditor.defer(10, this);
21325 Roo.TaskMgr.start(task);
21330 onResize : function(w, h)
21332 Roo.log('resize: ' +w + ',' + h );
21333 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21337 if(typeof w == 'number'){
21339 this.iframe.style.width = w + 'px';
21341 if(typeof h == 'number'){
21343 this.iframe.style.height = h + 'px';
21345 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21352 * Toggles the editor between standard and source edit mode.
21353 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21355 toggleSourceEdit : function(sourceEditMode){
21357 this.sourceEditMode = sourceEditMode === true;
21359 if(this.sourceEditMode){
21361 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21364 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21365 //this.iframe.className = '';
21368 //this.setSize(this.owner.wrap.getSize());
21369 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21376 * Protected method that will not generally be called directly. If you need/want
21377 * custom HTML cleanup, this is the method you should override.
21378 * @param {String} html The HTML to be cleaned
21379 * return {String} The cleaned HTML
21381 cleanHtml : function(html){
21382 html = String(html);
21383 if(html.length > 5){
21384 if(Roo.isSafari){ // strip safari nonsense
21385 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21388 if(html == ' '){
21395 * HTML Editor -> Textarea
21396 * Protected method that will not generally be called directly. Syncs the contents
21397 * of the editor iframe with the textarea.
21399 syncValue : function(){
21400 if(this.initialized){
21401 var bd = (this.doc.body || this.doc.documentElement);
21402 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21403 var html = bd.innerHTML;
21405 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21406 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21408 html = '<div style="'+m[0]+'">' + html + '</div>';
21411 html = this.cleanHtml(html);
21412 // fix up the special chars.. normaly like back quotes in word...
21413 // however we do not want to do this with chinese..
21414 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21415 var cc = b.charCodeAt();
21417 (cc >= 0x4E00 && cc < 0xA000 ) ||
21418 (cc >= 0x3400 && cc < 0x4E00 ) ||
21419 (cc >= 0xf900 && cc < 0xfb00 )
21425 if(this.owner.fireEvent('beforesync', this, html) !== false){
21426 this.el.dom.value = html;
21427 this.owner.fireEvent('sync', this, html);
21433 * Protected method that will not generally be called directly. Pushes the value of the textarea
21434 * into the iframe editor.
21436 pushValue : function(){
21437 if(this.initialized){
21438 var v = this.el.dom.value.trim();
21440 // if(v.length < 1){
21444 if(this.owner.fireEvent('beforepush', this, v) !== false){
21445 var d = (this.doc.body || this.doc.documentElement);
21447 this.cleanUpPaste();
21448 this.el.dom.value = d.innerHTML;
21449 this.owner.fireEvent('push', this, v);
21455 deferFocus : function(){
21456 this.focus.defer(10, this);
21460 focus : function(){
21461 if(this.win && !this.sourceEditMode){
21468 assignDocWin: function()
21470 var iframe = this.iframe;
21473 this.doc = iframe.contentWindow.document;
21474 this.win = iframe.contentWindow;
21476 // if (!Roo.get(this.frameId)) {
21479 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21480 // this.win = Roo.get(this.frameId).dom.contentWindow;
21482 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21486 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21487 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21492 initEditor : function(){
21493 //console.log("INIT EDITOR");
21494 this.assignDocWin();
21498 this.doc.designMode="on";
21500 this.doc.write(this.getDocMarkup());
21503 var dbody = (this.doc.body || this.doc.documentElement);
21504 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21505 // this copies styles from the containing element into thsi one..
21506 // not sure why we need all of this..
21507 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21509 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21510 //ss['background-attachment'] = 'fixed'; // w3c
21511 dbody.bgProperties = 'fixed'; // ie
21512 //Roo.DomHelper.applyStyles(dbody, ss);
21513 Roo.EventManager.on(this.doc, {
21514 //'mousedown': this.onEditorEvent,
21515 'mouseup': this.onEditorEvent,
21516 'dblclick': this.onEditorEvent,
21517 'click': this.onEditorEvent,
21518 'keyup': this.onEditorEvent,
21523 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21525 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21526 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21528 this.initialized = true;
21530 this.owner.fireEvent('initialize', this);
21535 onDestroy : function(){
21541 //for (var i =0; i < this.toolbars.length;i++) {
21542 // // fixme - ask toolbars for heights?
21543 // this.toolbars[i].onDestroy();
21546 //this.wrap.dom.innerHTML = '';
21547 //this.wrap.remove();
21552 onFirstFocus : function(){
21554 this.assignDocWin();
21557 this.activated = true;
21560 if(Roo.isGecko){ // prevent silly gecko errors
21562 var s = this.win.getSelection();
21563 if(!s.focusNode || s.focusNode.nodeType != 3){
21564 var r = s.getRangeAt(0);
21565 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21570 this.execCmd('useCSS', true);
21571 this.execCmd('styleWithCSS', false);
21574 this.owner.fireEvent('activate', this);
21578 adjustFont: function(btn){
21579 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21580 //if(Roo.isSafari){ // safari
21583 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21584 if(Roo.isSafari){ // safari
21585 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21586 v = (v < 10) ? 10 : v;
21587 v = (v > 48) ? 48 : v;
21588 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21593 v = Math.max(1, v+adjust);
21595 this.execCmd('FontSize', v );
21598 onEditorEvent : function(e)
21600 this.owner.fireEvent('editorevent', this, e);
21601 // this.updateToolbar();
21602 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21605 insertTag : function(tg)
21607 // could be a bit smarter... -> wrap the current selected tRoo..
21608 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21610 range = this.createRange(this.getSelection());
21611 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21612 wrappingNode.appendChild(range.extractContents());
21613 range.insertNode(wrappingNode);
21620 this.execCmd("formatblock", tg);
21624 insertText : function(txt)
21628 var range = this.createRange();
21629 range.deleteContents();
21630 //alert(Sender.getAttribute('label'));
21632 range.insertNode(this.doc.createTextNode(txt));
21638 * Executes a Midas editor command on the editor document and performs necessary focus and
21639 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21640 * @param {String} cmd The Midas command
21641 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21643 relayCmd : function(cmd, value){
21645 this.execCmd(cmd, value);
21646 this.owner.fireEvent('editorevent', this);
21647 //this.updateToolbar();
21648 this.owner.deferFocus();
21652 * Executes a Midas editor command directly on the editor document.
21653 * For visual commands, you should use {@link #relayCmd} instead.
21654 * <b>This should only be called after the editor is initialized.</b>
21655 * @param {String} cmd The Midas command
21656 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21658 execCmd : function(cmd, value){
21659 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21666 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21668 * @param {String} text | dom node..
21670 insertAtCursor : function(text)
21673 if(!this.activated){
21679 var r = this.doc.selection.createRange();
21690 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21694 // from jquery ui (MIT licenced)
21696 var win = this.win;
21698 if (win.getSelection && win.getSelection().getRangeAt) {
21699 range = win.getSelection().getRangeAt(0);
21700 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21701 range.insertNode(node);
21702 } else if (win.document.selection && win.document.selection.createRange) {
21703 // no firefox support
21704 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21705 win.document.selection.createRange().pasteHTML(txt);
21707 // no firefox support
21708 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21709 this.execCmd('InsertHTML', txt);
21718 mozKeyPress : function(e){
21720 var c = e.getCharCode(), cmd;
21723 c = String.fromCharCode(c).toLowerCase();
21737 this.cleanUpPaste.defer(100, this);
21745 e.preventDefault();
21753 fixKeys : function(){ // load time branching for fastest keydown performance
21755 return function(e){
21756 var k = e.getKey(), r;
21759 r = this.doc.selection.createRange();
21762 r.pasteHTML('    ');
21769 r = this.doc.selection.createRange();
21771 var target = r.parentElement();
21772 if(!target || target.tagName.toLowerCase() != 'li'){
21774 r.pasteHTML('<br />');
21780 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21781 this.cleanUpPaste.defer(100, this);
21787 }else if(Roo.isOpera){
21788 return function(e){
21789 var k = e.getKey();
21793 this.execCmd('InsertHTML','    ');
21796 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21797 this.cleanUpPaste.defer(100, this);
21802 }else if(Roo.isSafari){
21803 return function(e){
21804 var k = e.getKey();
21808 this.execCmd('InsertText','\t');
21812 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21813 this.cleanUpPaste.defer(100, this);
21821 getAllAncestors: function()
21823 var p = this.getSelectedNode();
21826 a.push(p); // push blank onto stack..
21827 p = this.getParentElement();
21831 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21835 a.push(this.doc.body);
21839 lastSelNode : false,
21842 getSelection : function()
21844 this.assignDocWin();
21845 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21848 getSelectedNode: function()
21850 // this may only work on Gecko!!!
21852 // should we cache this!!!!
21857 var range = this.createRange(this.getSelection()).cloneRange();
21860 var parent = range.parentElement();
21862 var testRange = range.duplicate();
21863 testRange.moveToElementText(parent);
21864 if (testRange.inRange(range)) {
21867 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21870 parent = parent.parentElement;
21875 // is ancestor a text element.
21876 var ac = range.commonAncestorContainer;
21877 if (ac.nodeType == 3) {
21878 ac = ac.parentNode;
21881 var ar = ac.childNodes;
21884 var other_nodes = [];
21885 var has_other_nodes = false;
21886 for (var i=0;i<ar.length;i++) {
21887 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21890 // fullly contained node.
21892 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21897 // probably selected..
21898 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21899 other_nodes.push(ar[i]);
21903 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21908 has_other_nodes = true;
21910 if (!nodes.length && other_nodes.length) {
21911 nodes= other_nodes;
21913 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21919 createRange: function(sel)
21921 // this has strange effects when using with
21922 // top toolbar - not sure if it's a great idea.
21923 //this.editor.contentWindow.focus();
21924 if (typeof sel != "undefined") {
21926 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21928 return this.doc.createRange();
21931 return this.doc.createRange();
21934 getParentElement: function()
21937 this.assignDocWin();
21938 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21940 var range = this.createRange(sel);
21943 var p = range.commonAncestorContainer;
21944 while (p.nodeType == 3) { // text node
21955 * Range intersection.. the hard stuff...
21959 * [ -- selected range --- ]
21963 * if end is before start or hits it. fail.
21964 * if start is after end or hits it fail.
21966 * if either hits (but other is outside. - then it's not
21972 // @see http://www.thismuchiknow.co.uk/?p=64.
21973 rangeIntersectsNode : function(range, node)
21975 var nodeRange = node.ownerDocument.createRange();
21977 nodeRange.selectNode(node);
21979 nodeRange.selectNodeContents(node);
21982 var rangeStartRange = range.cloneRange();
21983 rangeStartRange.collapse(true);
21985 var rangeEndRange = range.cloneRange();
21986 rangeEndRange.collapse(false);
21988 var nodeStartRange = nodeRange.cloneRange();
21989 nodeStartRange.collapse(true);
21991 var nodeEndRange = nodeRange.cloneRange();
21992 nodeEndRange.collapse(false);
21994 return rangeStartRange.compareBoundaryPoints(
21995 Range.START_TO_START, nodeEndRange) == -1 &&
21996 rangeEndRange.compareBoundaryPoints(
21997 Range.START_TO_START, nodeStartRange) == 1;
22001 rangeCompareNode : function(range, node)
22003 var nodeRange = node.ownerDocument.createRange();
22005 nodeRange.selectNode(node);
22007 nodeRange.selectNodeContents(node);
22011 range.collapse(true);
22013 nodeRange.collapse(true);
22015 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22016 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22018 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22020 var nodeIsBefore = ss == 1;
22021 var nodeIsAfter = ee == -1;
22023 if (nodeIsBefore && nodeIsAfter) {
22026 if (!nodeIsBefore && nodeIsAfter) {
22027 return 1; //right trailed.
22030 if (nodeIsBefore && !nodeIsAfter) {
22031 return 2; // left trailed.
22037 // private? - in a new class?
22038 cleanUpPaste : function()
22040 // cleans up the whole document..
22041 Roo.log('cleanuppaste');
22043 this.cleanUpChildren(this.doc.body);
22044 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22045 if (clean != this.doc.body.innerHTML) {
22046 this.doc.body.innerHTML = clean;
22051 cleanWordChars : function(input) {// change the chars to hex code
22052 var he = Roo.HtmlEditorCore;
22054 var output = input;
22055 Roo.each(he.swapCodes, function(sw) {
22056 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22058 output = output.replace(swapper, sw[1]);
22065 cleanUpChildren : function (n)
22067 if (!n.childNodes.length) {
22070 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22071 this.cleanUpChild(n.childNodes[i]);
22078 cleanUpChild : function (node)
22081 //console.log(node);
22082 if (node.nodeName == "#text") {
22083 // clean up silly Windows -- stuff?
22086 if (node.nodeName == "#comment") {
22087 node.parentNode.removeChild(node);
22088 // clean up silly Windows -- stuff?
22091 var lcname = node.tagName.toLowerCase();
22092 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22093 // whitelist of tags..
22095 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22097 node.parentNode.removeChild(node);
22102 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22104 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22105 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22107 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22108 // remove_keep_children = true;
22111 if (remove_keep_children) {
22112 this.cleanUpChildren(node);
22113 // inserts everything just before this node...
22114 while (node.childNodes.length) {
22115 var cn = node.childNodes[0];
22116 node.removeChild(cn);
22117 node.parentNode.insertBefore(cn, node);
22119 node.parentNode.removeChild(node);
22123 if (!node.attributes || !node.attributes.length) {
22124 this.cleanUpChildren(node);
22128 function cleanAttr(n,v)
22131 if (v.match(/^\./) || v.match(/^\//)) {
22134 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22137 if (v.match(/^#/)) {
22140 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22141 node.removeAttribute(n);
22145 var cwhite = this.cwhite;
22146 var cblack = this.cblack;
22148 function cleanStyle(n,v)
22150 if (v.match(/expression/)) { //XSS?? should we even bother..
22151 node.removeAttribute(n);
22155 var parts = v.split(/;/);
22158 Roo.each(parts, function(p) {
22159 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22163 var l = p.split(':').shift().replace(/\s+/g,'');
22164 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22166 if ( cwhite.length && cblack.indexOf(l) > -1) {
22167 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22168 //node.removeAttribute(n);
22172 // only allow 'c whitelisted system attributes'
22173 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22174 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22175 //node.removeAttribute(n);
22185 if (clean.length) {
22186 node.setAttribute(n, clean.join(';'));
22188 node.removeAttribute(n);
22194 for (var i = node.attributes.length-1; i > -1 ; i--) {
22195 var a = node.attributes[i];
22198 if (a.name.toLowerCase().substr(0,2)=='on') {
22199 node.removeAttribute(a.name);
22202 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22203 node.removeAttribute(a.name);
22206 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22207 cleanAttr(a.name,a.value); // fixme..
22210 if (a.name == 'style') {
22211 cleanStyle(a.name,a.value);
22214 /// clean up MS crap..
22215 // tecnically this should be a list of valid class'es..
22218 if (a.name == 'class') {
22219 if (a.value.match(/^Mso/)) {
22220 node.className = '';
22223 if (a.value.match(/^body$/)) {
22224 node.className = '';
22235 this.cleanUpChildren(node);
22241 * Clean up MS wordisms...
22243 cleanWord : function(node)
22248 this.cleanWord(this.doc.body);
22251 if (node.nodeName == "#text") {
22252 // clean up silly Windows -- stuff?
22255 if (node.nodeName == "#comment") {
22256 node.parentNode.removeChild(node);
22257 // clean up silly Windows -- stuff?
22261 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22262 node.parentNode.removeChild(node);
22266 // remove - but keep children..
22267 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22268 while (node.childNodes.length) {
22269 var cn = node.childNodes[0];
22270 node.removeChild(cn);
22271 node.parentNode.insertBefore(cn, node);
22273 node.parentNode.removeChild(node);
22274 this.iterateChildren(node, this.cleanWord);
22278 if (node.className.length) {
22280 var cn = node.className.split(/\W+/);
22282 Roo.each(cn, function(cls) {
22283 if (cls.match(/Mso[a-zA-Z]+/)) {
22288 node.className = cna.length ? cna.join(' ') : '';
22290 node.removeAttribute("class");
22294 if (node.hasAttribute("lang")) {
22295 node.removeAttribute("lang");
22298 if (node.hasAttribute("style")) {
22300 var styles = node.getAttribute("style").split(";");
22302 Roo.each(styles, function(s) {
22303 if (!s.match(/:/)) {
22306 var kv = s.split(":");
22307 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22310 // what ever is left... we allow.
22313 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22314 if (!nstyle.length) {
22315 node.removeAttribute('style');
22318 this.iterateChildren(node, this.cleanWord);
22324 * iterateChildren of a Node, calling fn each time, using this as the scole..
22325 * @param {DomNode} node node to iterate children of.
22326 * @param {Function} fn method of this class to call on each item.
22328 iterateChildren : function(node, fn)
22330 if (!node.childNodes.length) {
22333 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22334 fn.call(this, node.childNodes[i])
22340 * cleanTableWidths.
22342 * Quite often pasting from word etc.. results in tables with column and widths.
22343 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22346 cleanTableWidths : function(node)
22351 this.cleanTableWidths(this.doc.body);
22356 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22359 Roo.log(node.tagName);
22360 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22361 this.iterateChildren(node, this.cleanTableWidths);
22364 if (node.hasAttribute('width')) {
22365 node.removeAttribute('width');
22369 if (node.hasAttribute("style")) {
22372 var styles = node.getAttribute("style").split(";");
22374 Roo.each(styles, function(s) {
22375 if (!s.match(/:/)) {
22378 var kv = s.split(":");
22379 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22382 // what ever is left... we allow.
22385 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22386 if (!nstyle.length) {
22387 node.removeAttribute('style');
22391 this.iterateChildren(node, this.cleanTableWidths);
22399 domToHTML : function(currentElement, depth, nopadtext) {
22401 depth = depth || 0;
22402 nopadtext = nopadtext || false;
22404 if (!currentElement) {
22405 return this.domToHTML(this.doc.body);
22408 //Roo.log(currentElement);
22410 var allText = false;
22411 var nodeName = currentElement.nodeName;
22412 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22414 if (nodeName == '#text') {
22416 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22421 if (nodeName != 'BODY') {
22424 // Prints the node tagName, such as <A>, <IMG>, etc
22427 for(i = 0; i < currentElement.attributes.length;i++) {
22429 var aname = currentElement.attributes.item(i).name;
22430 if (!currentElement.attributes.item(i).value.length) {
22433 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22436 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22445 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22448 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22453 // Traverse the tree
22455 var currentElementChild = currentElement.childNodes.item(i);
22456 var allText = true;
22457 var innerHTML = '';
22459 while (currentElementChild) {
22460 // Formatting code (indent the tree so it looks nice on the screen)
22461 var nopad = nopadtext;
22462 if (lastnode == 'SPAN') {
22466 if (currentElementChild.nodeName == '#text') {
22467 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22468 toadd = nopadtext ? toadd : toadd.trim();
22469 if (!nopad && toadd.length > 80) {
22470 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22472 innerHTML += toadd;
22475 currentElementChild = currentElement.childNodes.item(i);
22481 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22483 // Recursively traverse the tree structure of the child node
22484 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22485 lastnode = currentElementChild.nodeName;
22487 currentElementChild=currentElement.childNodes.item(i);
22493 // The remaining code is mostly for formatting the tree
22494 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22499 ret+= "</"+tagName+">";
22505 applyBlacklists : function()
22507 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22508 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22512 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22513 if (b.indexOf(tag) > -1) {
22516 this.white.push(tag);
22520 Roo.each(w, function(tag) {
22521 if (b.indexOf(tag) > -1) {
22524 if (this.white.indexOf(tag) > -1) {
22527 this.white.push(tag);
22532 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22533 if (w.indexOf(tag) > -1) {
22536 this.black.push(tag);
22540 Roo.each(b, function(tag) {
22541 if (w.indexOf(tag) > -1) {
22544 if (this.black.indexOf(tag) > -1) {
22547 this.black.push(tag);
22552 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22553 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22557 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22558 if (b.indexOf(tag) > -1) {
22561 this.cwhite.push(tag);
22565 Roo.each(w, function(tag) {
22566 if (b.indexOf(tag) > -1) {
22569 if (this.cwhite.indexOf(tag) > -1) {
22572 this.cwhite.push(tag);
22577 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22578 if (w.indexOf(tag) > -1) {
22581 this.cblack.push(tag);
22585 Roo.each(b, function(tag) {
22586 if (w.indexOf(tag) > -1) {
22589 if (this.cblack.indexOf(tag) > -1) {
22592 this.cblack.push(tag);
22597 setStylesheets : function(stylesheets)
22599 if(typeof(stylesheets) == 'string'){
22600 Roo.get(this.iframe.contentDocument.head).createChild({
22602 rel : 'stylesheet',
22611 Roo.each(stylesheets, function(s) {
22616 Roo.get(_this.iframe.contentDocument.head).createChild({
22618 rel : 'stylesheet',
22627 removeStylesheets : function()
22631 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22636 // hide stuff that is not compatible
22650 * @event specialkey
22654 * @cfg {String} fieldClass @hide
22657 * @cfg {String} focusClass @hide
22660 * @cfg {String} autoCreate @hide
22663 * @cfg {String} inputType @hide
22666 * @cfg {String} invalidClass @hide
22669 * @cfg {String} invalidText @hide
22672 * @cfg {String} msgFx @hide
22675 * @cfg {String} validateOnBlur @hide
22679 Roo.HtmlEditorCore.white = [
22680 'area', 'br', 'img', 'input', 'hr', 'wbr',
22682 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22683 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22684 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22685 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22686 'table', 'ul', 'xmp',
22688 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22691 'dir', 'menu', 'ol', 'ul', 'dl',
22697 Roo.HtmlEditorCore.black = [
22698 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22700 'base', 'basefont', 'bgsound', 'blink', 'body',
22701 'frame', 'frameset', 'head', 'html', 'ilayer',
22702 'iframe', 'layer', 'link', 'meta', 'object',
22703 'script', 'style' ,'title', 'xml' // clean later..
22705 Roo.HtmlEditorCore.clean = [
22706 'script', 'style', 'title', 'xml'
22708 Roo.HtmlEditorCore.remove = [
22713 Roo.HtmlEditorCore.ablack = [
22717 Roo.HtmlEditorCore.aclean = [
22718 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22722 Roo.HtmlEditorCore.pwhite= [
22723 'http', 'https', 'mailto'
22726 // white listed style attributes.
22727 Roo.HtmlEditorCore.cwhite= [
22728 // 'text-align', /// default is to allow most things..
22734 // black listed style attributes.
22735 Roo.HtmlEditorCore.cblack= [
22736 // 'font-size' -- this can be set by the project
22740 Roo.HtmlEditorCore.swapCodes =[
22759 * @class Roo.bootstrap.HtmlEditor
22760 * @extends Roo.bootstrap.TextArea
22761 * Bootstrap HtmlEditor class
22764 * Create a new HtmlEditor
22765 * @param {Object} config The config object
22768 Roo.bootstrap.HtmlEditor = function(config){
22769 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22770 if (!this.toolbars) {
22771 this.toolbars = [];
22774 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22777 * @event initialize
22778 * Fires when the editor is fully initialized (including the iframe)
22779 * @param {HtmlEditor} this
22784 * Fires when the editor is first receives the focus. Any insertion must wait
22785 * until after this event.
22786 * @param {HtmlEditor} this
22790 * @event beforesync
22791 * Fires before the textarea is updated with content from the editor iframe. Return false
22792 * to cancel the sync.
22793 * @param {HtmlEditor} this
22794 * @param {String} html
22798 * @event beforepush
22799 * Fires before the iframe editor is updated with content from the textarea. Return false
22800 * to cancel the push.
22801 * @param {HtmlEditor} this
22802 * @param {String} html
22807 * Fires when the textarea is updated with content from the editor iframe.
22808 * @param {HtmlEditor} this
22809 * @param {String} html
22814 * Fires when the iframe editor is updated with content from the textarea.
22815 * @param {HtmlEditor} this
22816 * @param {String} html
22820 * @event editmodechange
22821 * Fires when the editor switches edit modes
22822 * @param {HtmlEditor} this
22823 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22825 editmodechange: true,
22827 * @event editorevent
22828 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22829 * @param {HtmlEditor} this
22833 * @event firstfocus
22834 * Fires when on first focus - needed by toolbars..
22835 * @param {HtmlEditor} this
22840 * Auto save the htmlEditor value as a file into Events
22841 * @param {HtmlEditor} this
22845 * @event savedpreview
22846 * preview the saved version of htmlEditor
22847 * @param {HtmlEditor} this
22854 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22858 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22863 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
22868 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22873 * @cfg {Number} height (in pixels)
22877 * @cfg {Number} width (in pixels)
22882 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22885 stylesheets: false,
22890 // private properties
22891 validationEvent : false,
22893 initialized : false,
22896 onFocus : Roo.emptyFn,
22898 hideMode:'offsets',
22900 tbContainer : false,
22902 toolbarContainer :function() {
22903 return this.wrap.select('.x-html-editor-tb',true).first();
22907 * Protected method that will not generally be called directly. It
22908 * is called when the editor creates its toolbar. Override this method if you need to
22909 * add custom toolbar buttons.
22910 * @param {HtmlEditor} editor
22912 createToolbar : function(){
22913 Roo.log('renewing');
22914 Roo.log("create toolbars");
22916 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22917 this.toolbars[0].render(this.toolbarContainer());
22921 // if (!editor.toolbars || !editor.toolbars.length) {
22922 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22925 // for (var i =0 ; i < editor.toolbars.length;i++) {
22926 // editor.toolbars[i] = Roo.factory(
22927 // typeof(editor.toolbars[i]) == 'string' ?
22928 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22929 // Roo.bootstrap.HtmlEditor);
22930 // editor.toolbars[i].init(editor);
22936 onRender : function(ct, position)
22938 // Roo.log("Call onRender: " + this.xtype);
22940 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22942 this.wrap = this.inputEl().wrap({
22943 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22946 this.editorcore.onRender(ct, position);
22948 if (this.resizable) {
22949 this.resizeEl = new Roo.Resizable(this.wrap, {
22953 minHeight : this.height,
22954 height: this.height,
22955 handles : this.resizable,
22958 resize : function(r, w, h) {
22959 _t.onResize(w,h); // -something
22965 this.createToolbar(this);
22968 if(!this.width && this.resizable){
22969 this.setSize(this.wrap.getSize());
22971 if (this.resizeEl) {
22972 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22973 // should trigger onReize..
22979 onResize : function(w, h)
22981 Roo.log('resize: ' +w + ',' + h );
22982 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22986 if(this.inputEl() ){
22987 if(typeof w == 'number'){
22988 var aw = w - this.wrap.getFrameWidth('lr');
22989 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22992 if(typeof h == 'number'){
22993 var tbh = -11; // fixme it needs to tool bar size!
22994 for (var i =0; i < this.toolbars.length;i++) {
22995 // fixme - ask toolbars for heights?
22996 tbh += this.toolbars[i].el.getHeight();
22997 //if (this.toolbars[i].footer) {
22998 // tbh += this.toolbars[i].footer.el.getHeight();
23006 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23007 ah -= 5; // knock a few pixes off for look..
23008 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23012 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23013 this.editorcore.onResize(ew,eh);
23018 * Toggles the editor between standard and source edit mode.
23019 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23021 toggleSourceEdit : function(sourceEditMode)
23023 this.editorcore.toggleSourceEdit(sourceEditMode);
23025 if(this.editorcore.sourceEditMode){
23026 Roo.log('editor - showing textarea');
23029 // Roo.log(this.syncValue());
23031 this.inputEl().removeClass(['hide', 'x-hidden']);
23032 this.inputEl().dom.removeAttribute('tabIndex');
23033 this.inputEl().focus();
23035 Roo.log('editor - hiding textarea');
23037 // Roo.log(this.pushValue());
23040 this.inputEl().addClass(['hide', 'x-hidden']);
23041 this.inputEl().dom.setAttribute('tabIndex', -1);
23042 //this.deferFocus();
23045 if(this.resizable){
23046 this.setSize(this.wrap.getSize());
23049 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23052 // private (for BoxComponent)
23053 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23055 // private (for BoxComponent)
23056 getResizeEl : function(){
23060 // private (for BoxComponent)
23061 getPositionEl : function(){
23066 initEvents : function(){
23067 this.originalValue = this.getValue();
23071 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23074 // markInvalid : Roo.emptyFn,
23076 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23079 // clearInvalid : Roo.emptyFn,
23081 setValue : function(v){
23082 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23083 this.editorcore.pushValue();
23088 deferFocus : function(){
23089 this.focus.defer(10, this);
23093 focus : function(){
23094 this.editorcore.focus();
23100 onDestroy : function(){
23106 for (var i =0; i < this.toolbars.length;i++) {
23107 // fixme - ask toolbars for heights?
23108 this.toolbars[i].onDestroy();
23111 this.wrap.dom.innerHTML = '';
23112 this.wrap.remove();
23117 onFirstFocus : function(){
23118 //Roo.log("onFirstFocus");
23119 this.editorcore.onFirstFocus();
23120 for (var i =0; i < this.toolbars.length;i++) {
23121 this.toolbars[i].onFirstFocus();
23127 syncValue : function()
23129 this.editorcore.syncValue();
23132 pushValue : function()
23134 this.editorcore.pushValue();
23138 // hide stuff that is not compatible
23152 * @event specialkey
23156 * @cfg {String} fieldClass @hide
23159 * @cfg {String} focusClass @hide
23162 * @cfg {String} autoCreate @hide
23165 * @cfg {String} inputType @hide
23168 * @cfg {String} invalidClass @hide
23171 * @cfg {String} invalidText @hide
23174 * @cfg {String} msgFx @hide
23177 * @cfg {String} validateOnBlur @hide
23186 Roo.namespace('Roo.bootstrap.htmleditor');
23188 * @class Roo.bootstrap.HtmlEditorToolbar1
23193 new Roo.bootstrap.HtmlEditor({
23196 new Roo.bootstrap.HtmlEditorToolbar1({
23197 disable : { fonts: 1 , format: 1, ..., ... , ...],
23203 * @cfg {Object} disable List of elements to disable..
23204 * @cfg {Array} btns List of additional buttons.
23208 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23211 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23214 Roo.apply(this, config);
23216 // default disabled, based on 'good practice'..
23217 this.disable = this.disable || {};
23218 Roo.applyIf(this.disable, {
23221 specialElements : true
23223 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23225 this.editor = config.editor;
23226 this.editorcore = config.editor.editorcore;
23228 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23230 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23231 // dont call parent... till later.
23233 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23238 editorcore : false,
23243 "h1","h2","h3","h4","h5","h6",
23245 "abbr", "acronym", "address", "cite", "samp", "var",
23249 onRender : function(ct, position)
23251 // Roo.log("Call onRender: " + this.xtype);
23253 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23255 this.el.dom.style.marginBottom = '0';
23257 var editorcore = this.editorcore;
23258 var editor= this.editor;
23261 var btn = function(id,cmd , toggle, handler, html){
23263 var event = toggle ? 'toggle' : 'click';
23268 xns: Roo.bootstrap,
23271 enableToggle:toggle !== false,
23273 pressed : toggle ? false : null,
23276 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23277 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23283 // var cb_box = function...
23288 xns: Roo.bootstrap,
23289 glyphicon : 'font',
23293 xns: Roo.bootstrap,
23297 Roo.each(this.formats, function(f) {
23298 style.menu.items.push({
23300 xns: Roo.bootstrap,
23301 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23306 editorcore.insertTag(this.tagname);
23313 children.push(style);
23315 btn('bold',false,true);
23316 btn('italic',false,true);
23317 btn('align-left', 'justifyleft',true);
23318 btn('align-center', 'justifycenter',true);
23319 btn('align-right' , 'justifyright',true);
23320 btn('link', false, false, function(btn) {
23321 //Roo.log("create link?");
23322 var url = prompt(this.createLinkText, this.defaultLinkValue);
23323 if(url && url != 'http:/'+'/'){
23324 this.editorcore.relayCmd('createlink', url);
23327 btn('list','insertunorderedlist',true);
23328 btn('pencil', false,true, function(btn){
23330 this.toggleSourceEdit(btn.pressed);
23333 if (this.editor.btns.length > 0) {
23334 for (var i = 0; i<this.editor.btns.length; i++) {
23335 children.push(this.editor.btns[i]);
23343 xns: Roo.bootstrap,
23348 xns: Roo.bootstrap,
23353 cog.menu.items.push({
23355 xns: Roo.bootstrap,
23356 html : Clean styles,
23361 editorcore.insertTag(this.tagname);
23370 this.xtype = 'NavSimplebar';
23372 for(var i=0;i< children.length;i++) {
23374 this.buttons.add(this.addxtypeChild(children[i]));
23378 editor.on('editorevent', this.updateToolbar, this);
23380 onBtnClick : function(id)
23382 this.editorcore.relayCmd(id);
23383 this.editorcore.focus();
23387 * Protected method that will not generally be called directly. It triggers
23388 * a toolbar update by reading the markup state of the current selection in the editor.
23390 updateToolbar: function(){
23392 if(!this.editorcore.activated){
23393 this.editor.onFirstFocus(); // is this neeed?
23397 var btns = this.buttons;
23398 var doc = this.editorcore.doc;
23399 btns.get('bold').setActive(doc.queryCommandState('bold'));
23400 btns.get('italic').setActive(doc.queryCommandState('italic'));
23401 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23403 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23404 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23405 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23407 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23408 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23411 var ans = this.editorcore.getAllAncestors();
23412 if (this.formatCombo) {
23415 var store = this.formatCombo.store;
23416 this.formatCombo.setValue("");
23417 for (var i =0; i < ans.length;i++) {
23418 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23420 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23428 // hides menus... - so this cant be on a menu...
23429 Roo.bootstrap.MenuMgr.hideAll();
23431 Roo.bootstrap.MenuMgr.hideAll();
23432 //this.editorsyncValue();
23434 onFirstFocus: function() {
23435 this.buttons.each(function(item){
23439 toggleSourceEdit : function(sourceEditMode){
23442 if(sourceEditMode){
23443 Roo.log("disabling buttons");
23444 this.buttons.each( function(item){
23445 if(item.cmd != 'pencil'){
23451 Roo.log("enabling buttons");
23452 if(this.editorcore.initialized){
23453 this.buttons.each( function(item){
23459 Roo.log("calling toggole on editor");
23460 // tell the editor that it's been pressed..
23461 this.editor.toggleSourceEdit(sourceEditMode);
23471 * @class Roo.bootstrap.Table.AbstractSelectionModel
23472 * @extends Roo.util.Observable
23473 * Abstract base class for grid SelectionModels. It provides the interface that should be
23474 * implemented by descendant classes. This class should not be directly instantiated.
23477 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23478 this.locked = false;
23479 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23483 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23484 /** @ignore Called by the grid automatically. Do not call directly. */
23485 init : function(grid){
23491 * Locks the selections.
23494 this.locked = true;
23498 * Unlocks the selections.
23500 unlock : function(){
23501 this.locked = false;
23505 * Returns true if the selections are locked.
23506 * @return {Boolean}
23508 isLocked : function(){
23509 return this.locked;
23513 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23514 * @class Roo.bootstrap.Table.RowSelectionModel
23515 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23516 * It supports multiple selections and keyboard selection/navigation.
23518 * @param {Object} config
23521 Roo.bootstrap.Table.RowSelectionModel = function(config){
23522 Roo.apply(this, config);
23523 this.selections = new Roo.util.MixedCollection(false, function(o){
23528 this.lastActive = false;
23532 * @event selectionchange
23533 * Fires when the selection changes
23534 * @param {SelectionModel} this
23536 "selectionchange" : true,
23538 * @event afterselectionchange
23539 * Fires after the selection changes (eg. by key press or clicking)
23540 * @param {SelectionModel} this
23542 "afterselectionchange" : true,
23544 * @event beforerowselect
23545 * Fires when a row is selected being selected, return false to cancel.
23546 * @param {SelectionModel} this
23547 * @param {Number} rowIndex The selected index
23548 * @param {Boolean} keepExisting False if other selections will be cleared
23550 "beforerowselect" : true,
23553 * Fires when a row is selected.
23554 * @param {SelectionModel} this
23555 * @param {Number} rowIndex The selected index
23556 * @param {Roo.data.Record} r The record
23558 "rowselect" : true,
23560 * @event rowdeselect
23561 * Fires when a row is deselected.
23562 * @param {SelectionModel} this
23563 * @param {Number} rowIndex The selected index
23565 "rowdeselect" : true
23567 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23568 this.locked = false;
23571 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23573 * @cfg {Boolean} singleSelect
23574 * True to allow selection of only one row at a time (defaults to false)
23576 singleSelect : false,
23579 initEvents : function()
23582 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23583 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23584 //}else{ // allow click to work like normal
23585 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23587 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23588 this.grid.on("rowclick", this.handleMouseDown, this);
23590 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23591 "up" : function(e){
23593 this.selectPrevious(e.shiftKey);
23594 }else if(this.last !== false && this.lastActive !== false){
23595 var last = this.last;
23596 this.selectRange(this.last, this.lastActive-1);
23597 this.grid.getView().focusRow(this.lastActive);
23598 if(last !== false){
23602 this.selectFirstRow();
23604 this.fireEvent("afterselectionchange", this);
23606 "down" : function(e){
23608 this.selectNext(e.shiftKey);
23609 }else if(this.last !== false && this.lastActive !== false){
23610 var last = this.last;
23611 this.selectRange(this.last, this.lastActive+1);
23612 this.grid.getView().focusRow(this.lastActive);
23613 if(last !== false){
23617 this.selectFirstRow();
23619 this.fireEvent("afterselectionchange", this);
23623 this.grid.store.on('load', function(){
23624 this.selections.clear();
23627 var view = this.grid.view;
23628 view.on("refresh", this.onRefresh, this);
23629 view.on("rowupdated", this.onRowUpdated, this);
23630 view.on("rowremoved", this.onRemove, this);
23635 onRefresh : function()
23637 var ds = this.grid.store, i, v = this.grid.view;
23638 var s = this.selections;
23639 s.each(function(r){
23640 if((i = ds.indexOfId(r.id)) != -1){
23649 onRemove : function(v, index, r){
23650 this.selections.remove(r);
23654 onRowUpdated : function(v, index, r){
23655 if(this.isSelected(r)){
23656 v.onRowSelect(index);
23662 * @param {Array} records The records to select
23663 * @param {Boolean} keepExisting (optional) True to keep existing selections
23665 selectRecords : function(records, keepExisting)
23668 this.clearSelections();
23670 var ds = this.grid.store;
23671 for(var i = 0, len = records.length; i < len; i++){
23672 this.selectRow(ds.indexOf(records[i]), true);
23677 * Gets the number of selected rows.
23680 getCount : function(){
23681 return this.selections.length;
23685 * Selects the first row in the grid.
23687 selectFirstRow : function(){
23692 * Select the last row.
23693 * @param {Boolean} keepExisting (optional) True to keep existing selections
23695 selectLastRow : function(keepExisting){
23696 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23697 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23701 * Selects the row immediately following the last selected row.
23702 * @param {Boolean} keepExisting (optional) True to keep existing selections
23704 selectNext : function(keepExisting)
23706 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23707 this.selectRow(this.last+1, keepExisting);
23708 this.grid.getView().focusRow(this.last);
23713 * Selects the row that precedes the last selected row.
23714 * @param {Boolean} keepExisting (optional) True to keep existing selections
23716 selectPrevious : function(keepExisting){
23718 this.selectRow(this.last-1, keepExisting);
23719 this.grid.getView().focusRow(this.last);
23724 * Returns the selected records
23725 * @return {Array} Array of selected records
23727 getSelections : function(){
23728 return [].concat(this.selections.items);
23732 * Returns the first selected record.
23735 getSelected : function(){
23736 return this.selections.itemAt(0);
23741 * Clears all selections.
23743 clearSelections : function(fast)
23749 var ds = this.grid.store;
23750 var s = this.selections;
23751 s.each(function(r){
23752 this.deselectRow(ds.indexOfId(r.id));
23756 this.selections.clear();
23763 * Selects all rows.
23765 selectAll : function(){
23769 this.selections.clear();
23770 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23771 this.selectRow(i, true);
23776 * Returns True if there is a selection.
23777 * @return {Boolean}
23779 hasSelection : function(){
23780 return this.selections.length > 0;
23784 * Returns True if the specified row is selected.
23785 * @param {Number/Record} record The record or index of the record to check
23786 * @return {Boolean}
23788 isSelected : function(index){
23789 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23790 return (r && this.selections.key(r.id) ? true : false);
23794 * Returns True if the specified record id is selected.
23795 * @param {String} id The id of record to check
23796 * @return {Boolean}
23798 isIdSelected : function(id){
23799 return (this.selections.key(id) ? true : false);
23804 handleMouseDBClick : function(e, t){
23808 handleMouseDown : function(e, t)
23810 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23811 if(this.isLocked() || rowIndex < 0 ){
23814 if(e.shiftKey && this.last !== false){
23815 var last = this.last;
23816 this.selectRange(last, rowIndex, e.ctrlKey);
23817 this.last = last; // reset the last
23821 var isSelected = this.isSelected(rowIndex);
23822 //Roo.log("select row:" + rowIndex);
23824 this.deselectRow(rowIndex);
23826 this.selectRow(rowIndex, true);
23830 if(e.button !== 0 && isSelected){
23831 alert('rowIndex 2: ' + rowIndex);
23832 view.focusRow(rowIndex);
23833 }else if(e.ctrlKey && isSelected){
23834 this.deselectRow(rowIndex);
23835 }else if(!isSelected){
23836 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23837 view.focusRow(rowIndex);
23841 this.fireEvent("afterselectionchange", this);
23844 handleDragableRowClick : function(grid, rowIndex, e)
23846 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23847 this.selectRow(rowIndex, false);
23848 grid.view.focusRow(rowIndex);
23849 this.fireEvent("afterselectionchange", this);
23854 * Selects multiple rows.
23855 * @param {Array} rows Array of the indexes of the row to select
23856 * @param {Boolean} keepExisting (optional) True to keep existing selections
23858 selectRows : function(rows, keepExisting){
23860 this.clearSelections();
23862 for(var i = 0, len = rows.length; i < len; i++){
23863 this.selectRow(rows[i], true);
23868 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23869 * @param {Number} startRow The index of the first row in the range
23870 * @param {Number} endRow The index of the last row in the range
23871 * @param {Boolean} keepExisting (optional) True to retain existing selections
23873 selectRange : function(startRow, endRow, keepExisting){
23878 this.clearSelections();
23880 if(startRow <= endRow){
23881 for(var i = startRow; i <= endRow; i++){
23882 this.selectRow(i, true);
23885 for(var i = startRow; i >= endRow; i--){
23886 this.selectRow(i, true);
23892 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23893 * @param {Number} startRow The index of the first row in the range
23894 * @param {Number} endRow The index of the last row in the range
23896 deselectRange : function(startRow, endRow, preventViewNotify){
23900 for(var i = startRow; i <= endRow; i++){
23901 this.deselectRow(i, preventViewNotify);
23907 * @param {Number} row The index of the row to select
23908 * @param {Boolean} keepExisting (optional) True to keep existing selections
23910 selectRow : function(index, keepExisting, preventViewNotify)
23912 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23915 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23916 if(!keepExisting || this.singleSelect){
23917 this.clearSelections();
23920 var r = this.grid.store.getAt(index);
23921 //console.log('selectRow - record id :' + r.id);
23923 this.selections.add(r);
23924 this.last = this.lastActive = index;
23925 if(!preventViewNotify){
23926 var proxy = new Roo.Element(
23927 this.grid.getRowDom(index)
23929 proxy.addClass('bg-info info');
23931 this.fireEvent("rowselect", this, index, r);
23932 this.fireEvent("selectionchange", this);
23938 * @param {Number} row The index of the row to deselect
23940 deselectRow : function(index, preventViewNotify)
23945 if(this.last == index){
23948 if(this.lastActive == index){
23949 this.lastActive = false;
23952 var r = this.grid.store.getAt(index);
23957 this.selections.remove(r);
23958 //.console.log('deselectRow - record id :' + r.id);
23959 if(!preventViewNotify){
23961 var proxy = new Roo.Element(
23962 this.grid.getRowDom(index)
23964 proxy.removeClass('bg-info info');
23966 this.fireEvent("rowdeselect", this, index);
23967 this.fireEvent("selectionchange", this);
23971 restoreLast : function(){
23973 this.last = this._last;
23978 acceptsNav : function(row, col, cm){
23979 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23983 onEditorKey : function(field, e){
23984 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23989 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23991 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23993 }else if(k == e.ENTER && !e.ctrlKey){
23997 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23999 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24001 }else if(k == e.ESC){
24005 g.startEditing(newCell[0], newCell[1]);
24011 * Ext JS Library 1.1.1
24012 * Copyright(c) 2006-2007, Ext JS, LLC.
24014 * Originally Released Under LGPL - original licence link has changed is not relivant.
24017 * <script type="text/javascript">
24021 * @class Roo.bootstrap.PagingToolbar
24022 * @extends Roo.bootstrap.NavSimplebar
24023 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24025 * Create a new PagingToolbar
24026 * @param {Object} config The config object
24027 * @param {Roo.data.Store} store
24029 Roo.bootstrap.PagingToolbar = function(config)
24031 // old args format still supported... - xtype is prefered..
24032 // created from xtype...
24034 this.ds = config.dataSource;
24036 if (config.store && !this.ds) {
24037 this.store= Roo.factory(config.store, Roo.data);
24038 this.ds = this.store;
24039 this.ds.xmodule = this.xmodule || false;
24042 this.toolbarItems = [];
24043 if (config.items) {
24044 this.toolbarItems = config.items;
24047 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24052 this.bind(this.ds);
24055 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24059 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24061 * @cfg {Roo.data.Store} dataSource
24062 * The underlying data store providing the paged data
24065 * @cfg {String/HTMLElement/Element} container
24066 * container The id or element that will contain the toolbar
24069 * @cfg {Boolean} displayInfo
24070 * True to display the displayMsg (defaults to false)
24073 * @cfg {Number} pageSize
24074 * The number of records to display per page (defaults to 20)
24078 * @cfg {String} displayMsg
24079 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24081 displayMsg : 'Displaying {0} - {1} of {2}',
24083 * @cfg {String} emptyMsg
24084 * The message to display when no records are found (defaults to "No data to display")
24086 emptyMsg : 'No data to display',
24088 * Customizable piece of the default paging text (defaults to "Page")
24091 beforePageText : "Page",
24093 * Customizable piece of the default paging text (defaults to "of %0")
24096 afterPageText : "of {0}",
24098 * Customizable piece of the default paging text (defaults to "First Page")
24101 firstText : "First Page",
24103 * Customizable piece of the default paging text (defaults to "Previous Page")
24106 prevText : "Previous Page",
24108 * Customizable piece of the default paging text (defaults to "Next Page")
24111 nextText : "Next Page",
24113 * Customizable piece of the default paging text (defaults to "Last Page")
24116 lastText : "Last Page",
24118 * Customizable piece of the default paging text (defaults to "Refresh")
24121 refreshText : "Refresh",
24125 onRender : function(ct, position)
24127 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24128 this.navgroup.parentId = this.id;
24129 this.navgroup.onRender(this.el, null);
24130 // add the buttons to the navgroup
24132 if(this.displayInfo){
24133 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24134 this.displayEl = this.el.select('.x-paging-info', true).first();
24135 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24136 // this.displayEl = navel.el.select('span',true).first();
24142 Roo.each(_this.buttons, function(e){ // this might need to use render????
24143 Roo.factory(e).onRender(_this.el, null);
24147 Roo.each(_this.toolbarItems, function(e) {
24148 _this.navgroup.addItem(e);
24152 this.first = this.navgroup.addItem({
24153 tooltip: this.firstText,
24155 icon : 'fa fa-backward',
24157 preventDefault: true,
24158 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24161 this.prev = this.navgroup.addItem({
24162 tooltip: this.prevText,
24164 icon : 'fa fa-step-backward',
24166 preventDefault: true,
24167 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24169 //this.addSeparator();
24172 var field = this.navgroup.addItem( {
24174 cls : 'x-paging-position',
24176 html : this.beforePageText +
24177 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24178 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24181 this.field = field.el.select('input', true).first();
24182 this.field.on("keydown", this.onPagingKeydown, this);
24183 this.field.on("focus", function(){this.dom.select();});
24186 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24187 //this.field.setHeight(18);
24188 //this.addSeparator();
24189 this.next = this.navgroup.addItem({
24190 tooltip: this.nextText,
24192 html : ' <i class="fa fa-step-forward">',
24194 preventDefault: true,
24195 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24197 this.last = this.navgroup.addItem({
24198 tooltip: this.lastText,
24199 icon : 'fa fa-forward',
24202 preventDefault: true,
24203 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24205 //this.addSeparator();
24206 this.loading = this.navgroup.addItem({
24207 tooltip: this.refreshText,
24208 icon: 'fa fa-refresh',
24209 preventDefault: true,
24210 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24216 updateInfo : function(){
24217 if(this.displayEl){
24218 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24219 var msg = count == 0 ?
24223 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24225 this.displayEl.update(msg);
24230 onLoad : function(ds, r, o)
24232 this.cursor = o.params ? o.params.start : 0;
24233 var d = this.getPageData(),
24238 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24239 this.field.dom.value = ap;
24240 this.first.setDisabled(ap == 1);
24241 this.prev.setDisabled(ap == 1);
24242 this.next.setDisabled(ap == ps);
24243 this.last.setDisabled(ap == ps);
24244 this.loading.enable();
24249 getPageData : function(){
24250 var total = this.ds.getTotalCount();
24253 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24254 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24259 onLoadError : function(){
24260 this.loading.enable();
24264 onPagingKeydown : function(e){
24265 var k = e.getKey();
24266 var d = this.getPageData();
24268 var v = this.field.dom.value, pageNum;
24269 if(!v || isNaN(pageNum = parseInt(v, 10))){
24270 this.field.dom.value = d.activePage;
24273 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24274 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24277 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))
24279 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24280 this.field.dom.value = pageNum;
24281 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24284 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24286 var v = this.field.dom.value, pageNum;
24287 var increment = (e.shiftKey) ? 10 : 1;
24288 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24291 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24292 this.field.dom.value = d.activePage;
24295 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24297 this.field.dom.value = parseInt(v, 10) + increment;
24298 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24299 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24306 beforeLoad : function(){
24308 this.loading.disable();
24313 onClick : function(which){
24322 ds.load({params:{start: 0, limit: this.pageSize}});
24325 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24328 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24331 var total = ds.getTotalCount();
24332 var extra = total % this.pageSize;
24333 var lastStart = extra ? (total - extra) : total-this.pageSize;
24334 ds.load({params:{start: lastStart, limit: this.pageSize}});
24337 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24343 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24344 * @param {Roo.data.Store} store The data store to unbind
24346 unbind : function(ds){
24347 ds.un("beforeload", this.beforeLoad, this);
24348 ds.un("load", this.onLoad, this);
24349 ds.un("loadexception", this.onLoadError, this);
24350 ds.un("remove", this.updateInfo, this);
24351 ds.un("add", this.updateInfo, this);
24352 this.ds = undefined;
24356 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24357 * @param {Roo.data.Store} store The data store to bind
24359 bind : function(ds){
24360 ds.on("beforeload", this.beforeLoad, this);
24361 ds.on("load", this.onLoad, this);
24362 ds.on("loadexception", this.onLoadError, this);
24363 ds.on("remove", this.updateInfo, this);
24364 ds.on("add", this.updateInfo, this);
24375 * @class Roo.bootstrap.MessageBar
24376 * @extends Roo.bootstrap.Component
24377 * Bootstrap MessageBar class
24378 * @cfg {String} html contents of the MessageBar
24379 * @cfg {String} weight (info | success | warning | danger) default info
24380 * @cfg {String} beforeClass insert the bar before the given class
24381 * @cfg {Boolean} closable (true | false) default false
24382 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24385 * Create a new Element
24386 * @param {Object} config The config object
24389 Roo.bootstrap.MessageBar = function(config){
24390 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24393 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24399 beforeClass: 'bootstrap-sticky-wrap',
24401 getAutoCreate : function(){
24405 cls: 'alert alert-dismissable alert-' + this.weight,
24410 html: this.html || ''
24416 cfg.cls += ' alert-messages-fixed';
24430 onRender : function(ct, position)
24432 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24435 var cfg = Roo.apply({}, this.getAutoCreate());
24439 cfg.cls += ' ' + this.cls;
24442 cfg.style = this.style;
24444 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24446 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24449 this.el.select('>button.close').on('click', this.hide, this);
24455 if (!this.rendered) {
24461 this.fireEvent('show', this);
24467 if (!this.rendered) {
24473 this.fireEvent('hide', this);
24476 update : function()
24478 // var e = this.el.dom.firstChild;
24480 // if(this.closable){
24481 // e = e.nextSibling;
24484 // e.data = this.html || '';
24486 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24502 * @class Roo.bootstrap.Graph
24503 * @extends Roo.bootstrap.Component
24504 * Bootstrap Graph class
24508 @cfg {String} graphtype bar | vbar | pie
24509 @cfg {number} g_x coodinator | centre x (pie)
24510 @cfg {number} g_y coodinator | centre y (pie)
24511 @cfg {number} g_r radius (pie)
24512 @cfg {number} g_height height of the chart (respected by all elements in the set)
24513 @cfg {number} g_width width of the chart (respected by all elements in the set)
24514 @cfg {Object} title The title of the chart
24517 -opts (object) options for the chart
24519 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24520 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24522 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.
24523 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24525 o stretch (boolean)
24527 -opts (object) options for the pie
24530 o startAngle (number)
24531 o endAngle (number)
24535 * Create a new Input
24536 * @param {Object} config The config object
24539 Roo.bootstrap.Graph = function(config){
24540 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24546 * The img click event for the img.
24547 * @param {Roo.EventObject} e
24553 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24564 //g_colors: this.colors,
24571 getAutoCreate : function(){
24582 onRender : function(ct,position){
24585 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24587 if (typeof(Raphael) == 'undefined') {
24588 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24592 this.raphael = Raphael(this.el.dom);
24594 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24595 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24596 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24597 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24599 r.text(160, 10, "Single Series Chart").attr(txtattr);
24600 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24601 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24602 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24604 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24605 r.barchart(330, 10, 300, 220, data1);
24606 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24607 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24610 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24611 // r.barchart(30, 30, 560, 250, xdata, {
24612 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24613 // axis : "0 0 1 1",
24614 // axisxlabels : xdata
24615 // //yvalues : cols,
24618 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24620 // this.load(null,xdata,{
24621 // axis : "0 0 1 1",
24622 // axisxlabels : xdata
24627 load : function(graphtype,xdata,opts)
24629 this.raphael.clear();
24631 graphtype = this.graphtype;
24636 var r = this.raphael,
24637 fin = function () {
24638 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24640 fout = function () {
24641 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24643 pfin = function() {
24644 this.sector.stop();
24645 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24648 this.label[0].stop();
24649 this.label[0].attr({ r: 7.5 });
24650 this.label[1].attr({ "font-weight": 800 });
24653 pfout = function() {
24654 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24657 this.label[0].animate({ r: 5 }, 500, "bounce");
24658 this.label[1].attr({ "font-weight": 400 });
24664 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24667 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24670 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24671 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24673 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24680 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24685 setTitle: function(o)
24690 initEvents: function() {
24693 this.el.on('click', this.onClick, this);
24697 onClick : function(e)
24699 Roo.log('img onclick');
24700 this.fireEvent('click', this, e);
24712 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24715 * @class Roo.bootstrap.dash.NumberBox
24716 * @extends Roo.bootstrap.Component
24717 * Bootstrap NumberBox class
24718 * @cfg {String} headline Box headline
24719 * @cfg {String} content Box content
24720 * @cfg {String} icon Box icon
24721 * @cfg {String} footer Footer text
24722 * @cfg {String} fhref Footer href
24725 * Create a new NumberBox
24726 * @param {Object} config The config object
24730 Roo.bootstrap.dash.NumberBox = function(config){
24731 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24735 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24744 getAutoCreate : function(){
24748 cls : 'small-box ',
24756 cls : 'roo-headline',
24757 html : this.headline
24761 cls : 'roo-content',
24762 html : this.content
24776 cls : 'ion ' + this.icon
24785 cls : 'small-box-footer',
24786 href : this.fhref || '#',
24790 cfg.cn.push(footer);
24797 onRender : function(ct,position){
24798 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24805 setHeadline: function (value)
24807 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24810 setFooter: function (value, href)
24812 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24815 this.el.select('a.small-box-footer',true).first().attr('href', href);
24820 setContent: function (value)
24822 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24825 initEvents: function()
24839 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24842 * @class Roo.bootstrap.dash.TabBox
24843 * @extends Roo.bootstrap.Component
24844 * Bootstrap TabBox class
24845 * @cfg {String} title Title of the TabBox
24846 * @cfg {String} icon Icon of the TabBox
24847 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24848 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24851 * Create a new TabBox
24852 * @param {Object} config The config object
24856 Roo.bootstrap.dash.TabBox = function(config){
24857 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24862 * When a pane is added
24863 * @param {Roo.bootstrap.dash.TabPane} pane
24867 * @event activatepane
24868 * When a pane is activated
24869 * @param {Roo.bootstrap.dash.TabPane} pane
24871 "activatepane" : true
24879 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24884 tabScrollable : false,
24886 getChildContainer : function()
24888 return this.el.select('.tab-content', true).first();
24891 getAutoCreate : function(){
24895 cls: 'pull-left header',
24903 cls: 'fa ' + this.icon
24909 cls: 'nav nav-tabs pull-right',
24915 if(this.tabScrollable){
24922 cls: 'nav nav-tabs pull-right',
24933 cls: 'nav-tabs-custom',
24938 cls: 'tab-content no-padding',
24946 initEvents : function()
24948 //Roo.log('add add pane handler');
24949 this.on('addpane', this.onAddPane, this);
24952 * Updates the box title
24953 * @param {String} html to set the title to.
24955 setTitle : function(value)
24957 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24959 onAddPane : function(pane)
24961 this.panes.push(pane);
24962 //Roo.log('addpane');
24964 // tabs are rendere left to right..
24965 if(!this.showtabs){
24969 var ctr = this.el.select('.nav-tabs', true).first();
24972 var existing = ctr.select('.nav-tab',true);
24973 var qty = existing.getCount();;
24976 var tab = ctr.createChild({
24978 cls : 'nav-tab' + (qty ? '' : ' active'),
24986 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24989 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24991 pane.el.addClass('active');
24996 onTabClick : function(ev,un,ob,pane)
24998 //Roo.log('tab - prev default');
24999 ev.preventDefault();
25002 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25003 pane.tab.addClass('active');
25004 //Roo.log(pane.title);
25005 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25006 // technically we should have a deactivate event.. but maybe add later.
25007 // and it should not de-activate the selected tab...
25008 this.fireEvent('activatepane', pane);
25009 pane.el.addClass('active');
25010 pane.fireEvent('activate');
25015 getActivePane : function()
25018 Roo.each(this.panes, function(p) {
25019 if(p.el.hasClass('active')){
25040 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25042 * @class Roo.bootstrap.TabPane
25043 * @extends Roo.bootstrap.Component
25044 * Bootstrap TabPane class
25045 * @cfg {Boolean} active (false | true) Default false
25046 * @cfg {String} title title of panel
25050 * Create a new TabPane
25051 * @param {Object} config The config object
25054 Roo.bootstrap.dash.TabPane = function(config){
25055 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25061 * When a pane is activated
25062 * @param {Roo.bootstrap.dash.TabPane} pane
25069 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25074 // the tabBox that this is attached to.
25077 getAutoCreate : function()
25085 cfg.cls += ' active';
25090 initEvents : function()
25092 //Roo.log('trigger add pane handler');
25093 this.parent().fireEvent('addpane', this)
25097 * Updates the tab title
25098 * @param {String} html to set the title to.
25100 setTitle: function(str)
25106 this.tab.select('a', true).first().dom.innerHTML = str;
25123 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25126 * @class Roo.bootstrap.menu.Menu
25127 * @extends Roo.bootstrap.Component
25128 * Bootstrap Menu class - container for Menu
25129 * @cfg {String} html Text of the menu
25130 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25131 * @cfg {String} icon Font awesome icon
25132 * @cfg {String} pos Menu align to (top | bottom) default bottom
25136 * Create a new Menu
25137 * @param {Object} config The config object
25141 Roo.bootstrap.menu.Menu = function(config){
25142 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25146 * @event beforeshow
25147 * Fires before this menu is displayed
25148 * @param {Roo.bootstrap.menu.Menu} this
25152 * @event beforehide
25153 * Fires before this menu is hidden
25154 * @param {Roo.bootstrap.menu.Menu} this
25159 * Fires after this menu is displayed
25160 * @param {Roo.bootstrap.menu.Menu} this
25165 * Fires after this menu is hidden
25166 * @param {Roo.bootstrap.menu.Menu} this
25171 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25172 * @param {Roo.bootstrap.menu.Menu} this
25173 * @param {Roo.EventObject} e
25180 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25184 weight : 'default',
25189 getChildContainer : function() {
25190 if(this.isSubMenu){
25194 return this.el.select('ul.dropdown-menu', true).first();
25197 getAutoCreate : function()
25202 cls : 'roo-menu-text',
25210 cls : 'fa ' + this.icon
25221 cls : 'dropdown-button btn btn-' + this.weight,
25226 cls : 'dropdown-toggle btn btn-' + this.weight,
25236 cls : 'dropdown-menu'
25242 if(this.pos == 'top'){
25243 cfg.cls += ' dropup';
25246 if(this.isSubMenu){
25249 cls : 'dropdown-menu'
25256 onRender : function(ct, position)
25258 this.isSubMenu = ct.hasClass('dropdown-submenu');
25260 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25263 initEvents : function()
25265 if(this.isSubMenu){
25269 this.hidden = true;
25271 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25272 this.triggerEl.on('click', this.onTriggerPress, this);
25274 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25275 this.buttonEl.on('click', this.onClick, this);
25281 if(this.isSubMenu){
25285 return this.el.select('ul.dropdown-menu', true).first();
25288 onClick : function(e)
25290 this.fireEvent("click", this, e);
25293 onTriggerPress : function(e)
25295 if (this.isVisible()) {
25302 isVisible : function(){
25303 return !this.hidden;
25308 this.fireEvent("beforeshow", this);
25310 this.hidden = false;
25311 this.el.addClass('open');
25313 Roo.get(document).on("mouseup", this.onMouseUp, this);
25315 this.fireEvent("show", this);
25322 this.fireEvent("beforehide", this);
25324 this.hidden = true;
25325 this.el.removeClass('open');
25327 Roo.get(document).un("mouseup", this.onMouseUp);
25329 this.fireEvent("hide", this);
25332 onMouseUp : function()
25346 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25349 * @class Roo.bootstrap.menu.Item
25350 * @extends Roo.bootstrap.Component
25351 * Bootstrap MenuItem class
25352 * @cfg {Boolean} submenu (true | false) default false
25353 * @cfg {String} html text of the item
25354 * @cfg {String} href the link
25355 * @cfg {Boolean} disable (true | false) default false
25356 * @cfg {Boolean} preventDefault (true | false) default true
25357 * @cfg {String} icon Font awesome icon
25358 * @cfg {String} pos Submenu align to (left | right) default right
25362 * Create a new Item
25363 * @param {Object} config The config object
25367 Roo.bootstrap.menu.Item = function(config){
25368 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25372 * Fires when the mouse is hovering over this menu
25373 * @param {Roo.bootstrap.menu.Item} this
25374 * @param {Roo.EventObject} e
25379 * Fires when the mouse exits this menu
25380 * @param {Roo.bootstrap.menu.Item} this
25381 * @param {Roo.EventObject} e
25387 * The raw click event for the entire grid.
25388 * @param {Roo.EventObject} e
25394 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25399 preventDefault: true,
25404 getAutoCreate : function()
25409 cls : 'roo-menu-item-text',
25417 cls : 'fa ' + this.icon
25426 href : this.href || '#',
25433 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25437 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25439 if(this.pos == 'left'){
25440 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25447 initEvents : function()
25449 this.el.on('mouseover', this.onMouseOver, this);
25450 this.el.on('mouseout', this.onMouseOut, this);
25452 this.el.select('a', true).first().on('click', this.onClick, this);
25456 onClick : function(e)
25458 if(this.preventDefault){
25459 e.preventDefault();
25462 this.fireEvent("click", this, e);
25465 onMouseOver : function(e)
25467 if(this.submenu && this.pos == 'left'){
25468 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25471 this.fireEvent("mouseover", this, e);
25474 onMouseOut : function(e)
25476 this.fireEvent("mouseout", this, e);
25488 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25491 * @class Roo.bootstrap.menu.Separator
25492 * @extends Roo.bootstrap.Component
25493 * Bootstrap Separator class
25496 * Create a new Separator
25497 * @param {Object} config The config object
25501 Roo.bootstrap.menu.Separator = function(config){
25502 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25505 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25507 getAutoCreate : function(){
25528 * @class Roo.bootstrap.Tooltip
25529 * Bootstrap Tooltip class
25530 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25531 * to determine which dom element triggers the tooltip.
25533 * It needs to add support for additional attributes like tooltip-position
25536 * Create a new Toolti
25537 * @param {Object} config The config object
25540 Roo.bootstrap.Tooltip = function(config){
25541 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25543 this.alignment = Roo.bootstrap.Tooltip.alignment;
25545 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25546 this.alignment = config.alignment;
25551 Roo.apply(Roo.bootstrap.Tooltip, {
25553 * @function init initialize tooltip monitoring.
25557 currentTip : false,
25558 currentRegion : false,
25564 Roo.get(document).on('mouseover', this.enter ,this);
25565 Roo.get(document).on('mouseout', this.leave, this);
25568 this.currentTip = new Roo.bootstrap.Tooltip();
25571 enter : function(ev)
25573 var dom = ev.getTarget();
25575 //Roo.log(['enter',dom]);
25576 var el = Roo.fly(dom);
25577 if (this.currentEl) {
25579 //Roo.log(this.currentEl);
25580 //Roo.log(this.currentEl.contains(dom));
25581 if (this.currentEl == el) {
25584 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25590 if (this.currentTip.el) {
25591 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25595 if(!el || el.dom == document){
25601 // you can not look for children, as if el is the body.. then everythign is the child..
25602 if (!el.attr('tooltip')) { //
25603 if (!el.select("[tooltip]").elements.length) {
25606 // is the mouse over this child...?
25607 bindEl = el.select("[tooltip]").first();
25608 var xy = ev.getXY();
25609 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25610 //Roo.log("not in region.");
25613 //Roo.log("child element over..");
25616 this.currentEl = bindEl;
25617 this.currentTip.bind(bindEl);
25618 this.currentRegion = Roo.lib.Region.getRegion(dom);
25619 this.currentTip.enter();
25622 leave : function(ev)
25624 var dom = ev.getTarget();
25625 //Roo.log(['leave',dom]);
25626 if (!this.currentEl) {
25631 if (dom != this.currentEl.dom) {
25634 var xy = ev.getXY();
25635 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25638 // only activate leave if mouse cursor is outside... bounding box..
25643 if (this.currentTip) {
25644 this.currentTip.leave();
25646 //Roo.log('clear currentEl');
25647 this.currentEl = false;
25652 'left' : ['r-l', [-2,0], 'right'],
25653 'right' : ['l-r', [2,0], 'left'],
25654 'bottom' : ['t-b', [0,2], 'top'],
25655 'top' : [ 'b-t', [0,-2], 'bottom']
25661 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25666 delay : null, // can be { show : 300 , hide: 500}
25670 hoverState : null, //???
25672 placement : 'bottom',
25676 getAutoCreate : function(){
25683 cls : 'tooltip-arrow'
25686 cls : 'tooltip-inner'
25693 bind : function(el)
25699 enter : function () {
25701 if (this.timeout != null) {
25702 clearTimeout(this.timeout);
25705 this.hoverState = 'in';
25706 //Roo.log("enter - show");
25707 if (!this.delay || !this.delay.show) {
25712 this.timeout = setTimeout(function () {
25713 if (_t.hoverState == 'in') {
25716 }, this.delay.show);
25720 clearTimeout(this.timeout);
25722 this.hoverState = 'out';
25723 if (!this.delay || !this.delay.hide) {
25729 this.timeout = setTimeout(function () {
25730 //Roo.log("leave - timeout");
25732 if (_t.hoverState == 'out') {
25734 Roo.bootstrap.Tooltip.currentEl = false;
25739 show : function (msg)
25742 this.render(document.body);
25745 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25747 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25749 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25751 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25753 var placement = typeof this.placement == 'function' ?
25754 this.placement.call(this, this.el, on_el) :
25757 var autoToken = /\s?auto?\s?/i;
25758 var autoPlace = autoToken.test(placement);
25760 placement = placement.replace(autoToken, '') || 'top';
25764 //this.el.setXY([0,0]);
25766 //this.el.dom.style.display='block';
25768 //this.el.appendTo(on_el);
25770 var p = this.getPosition();
25771 var box = this.el.getBox();
25777 var align = this.alignment[placement];
25779 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25781 if(placement == 'top' || placement == 'bottom'){
25783 placement = 'right';
25786 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25787 placement = 'left';
25790 var scroll = Roo.select('body', true).first().getScroll();
25792 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25798 this.el.alignTo(this.bindEl, align[0],align[1]);
25799 //var arrow = this.el.select('.arrow',true).first();
25800 //arrow.set(align[2],
25802 this.el.addClass(placement);
25804 this.el.addClass('in fade');
25806 this.hoverState = null;
25808 if (this.el.hasClass('fade')) {
25819 //this.el.setXY([0,0]);
25820 this.el.removeClass('in');
25836 * @class Roo.bootstrap.LocationPicker
25837 * @extends Roo.bootstrap.Component
25838 * Bootstrap LocationPicker class
25839 * @cfg {Number} latitude Position when init default 0
25840 * @cfg {Number} longitude Position when init default 0
25841 * @cfg {Number} zoom default 15
25842 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25843 * @cfg {Boolean} mapTypeControl default false
25844 * @cfg {Boolean} disableDoubleClickZoom default false
25845 * @cfg {Boolean} scrollwheel default true
25846 * @cfg {Boolean} streetViewControl default false
25847 * @cfg {Number} radius default 0
25848 * @cfg {String} locationName
25849 * @cfg {Boolean} draggable default true
25850 * @cfg {Boolean} enableAutocomplete default false
25851 * @cfg {Boolean} enableReverseGeocode default true
25852 * @cfg {String} markerTitle
25855 * Create a new LocationPicker
25856 * @param {Object} config The config object
25860 Roo.bootstrap.LocationPicker = function(config){
25862 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25867 * Fires when the picker initialized.
25868 * @param {Roo.bootstrap.LocationPicker} this
25869 * @param {Google Location} location
25873 * @event positionchanged
25874 * Fires when the picker position changed.
25875 * @param {Roo.bootstrap.LocationPicker} this
25876 * @param {Google Location} location
25878 positionchanged : true,
25881 * Fires when the map resize.
25882 * @param {Roo.bootstrap.LocationPicker} this
25887 * Fires when the map show.
25888 * @param {Roo.bootstrap.LocationPicker} this
25893 * Fires when the map hide.
25894 * @param {Roo.bootstrap.LocationPicker} this
25899 * Fires when click the map.
25900 * @param {Roo.bootstrap.LocationPicker} this
25901 * @param {Map event} e
25905 * @event mapRightClick
25906 * Fires when right click the map.
25907 * @param {Roo.bootstrap.LocationPicker} this
25908 * @param {Map event} e
25910 mapRightClick : true,
25912 * @event markerClick
25913 * Fires when click the marker.
25914 * @param {Roo.bootstrap.LocationPicker} this
25915 * @param {Map event} e
25917 markerClick : true,
25919 * @event markerRightClick
25920 * Fires when right click the marker.
25921 * @param {Roo.bootstrap.LocationPicker} this
25922 * @param {Map event} e
25924 markerRightClick : true,
25926 * @event OverlayViewDraw
25927 * Fires when OverlayView Draw
25928 * @param {Roo.bootstrap.LocationPicker} this
25930 OverlayViewDraw : true,
25932 * @event OverlayViewOnAdd
25933 * Fires when OverlayView Draw
25934 * @param {Roo.bootstrap.LocationPicker} this
25936 OverlayViewOnAdd : true,
25938 * @event OverlayViewOnRemove
25939 * Fires when OverlayView Draw
25940 * @param {Roo.bootstrap.LocationPicker} this
25942 OverlayViewOnRemove : true,
25944 * @event OverlayViewShow
25945 * Fires when OverlayView Draw
25946 * @param {Roo.bootstrap.LocationPicker} this
25947 * @param {Pixel} cpx
25949 OverlayViewShow : true,
25951 * @event OverlayViewHide
25952 * Fires when OverlayView Draw
25953 * @param {Roo.bootstrap.LocationPicker} this
25955 OverlayViewHide : true,
25957 * @event loadexception
25958 * Fires when load google lib failed.
25959 * @param {Roo.bootstrap.LocationPicker} this
25961 loadexception : true
25966 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25968 gMapContext: false,
25974 mapTypeControl: false,
25975 disableDoubleClickZoom: false,
25977 streetViewControl: false,
25981 enableAutocomplete: false,
25982 enableReverseGeocode: true,
25985 getAutoCreate: function()
25990 cls: 'roo-location-picker'
25996 initEvents: function(ct, position)
25998 if(!this.el.getWidth() || this.isApplied()){
26002 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26007 initial: function()
26009 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26010 this.fireEvent('loadexception', this);
26014 if(!this.mapTypeId){
26015 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26018 this.gMapContext = this.GMapContext();
26020 this.initOverlayView();
26022 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26026 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26027 _this.setPosition(_this.gMapContext.marker.position);
26030 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26031 _this.fireEvent('mapClick', this, event);
26035 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26036 _this.fireEvent('mapRightClick', this, event);
26040 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26041 _this.fireEvent('markerClick', this, event);
26045 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26046 _this.fireEvent('markerRightClick', this, event);
26050 this.setPosition(this.gMapContext.location);
26052 this.fireEvent('initial', this, this.gMapContext.location);
26055 initOverlayView: function()
26059 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26063 _this.fireEvent('OverlayViewDraw', _this);
26068 _this.fireEvent('OverlayViewOnAdd', _this);
26071 onRemove: function()
26073 _this.fireEvent('OverlayViewOnRemove', _this);
26076 show: function(cpx)
26078 _this.fireEvent('OverlayViewShow', _this, cpx);
26083 _this.fireEvent('OverlayViewHide', _this);
26089 fromLatLngToContainerPixel: function(event)
26091 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26094 isApplied: function()
26096 return this.getGmapContext() == false ? false : true;
26099 getGmapContext: function()
26101 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26104 GMapContext: function()
26106 var position = new google.maps.LatLng(this.latitude, this.longitude);
26108 var _map = new google.maps.Map(this.el.dom, {
26111 mapTypeId: this.mapTypeId,
26112 mapTypeControl: this.mapTypeControl,
26113 disableDoubleClickZoom: this.disableDoubleClickZoom,
26114 scrollwheel: this.scrollwheel,
26115 streetViewControl: this.streetViewControl,
26116 locationName: this.locationName,
26117 draggable: this.draggable,
26118 enableAutocomplete: this.enableAutocomplete,
26119 enableReverseGeocode: this.enableReverseGeocode
26122 var _marker = new google.maps.Marker({
26123 position: position,
26125 title: this.markerTitle,
26126 draggable: this.draggable
26133 location: position,
26134 radius: this.radius,
26135 locationName: this.locationName,
26136 addressComponents: {
26137 formatted_address: null,
26138 addressLine1: null,
26139 addressLine2: null,
26141 streetNumber: null,
26145 stateOrProvince: null
26148 domContainer: this.el.dom,
26149 geodecoder: new google.maps.Geocoder()
26153 drawCircle: function(center, radius, options)
26155 if (this.gMapContext.circle != null) {
26156 this.gMapContext.circle.setMap(null);
26160 options = Roo.apply({}, options, {
26161 strokeColor: "#0000FF",
26162 strokeOpacity: .35,
26164 fillColor: "#0000FF",
26168 options.map = this.gMapContext.map;
26169 options.radius = radius;
26170 options.center = center;
26171 this.gMapContext.circle = new google.maps.Circle(options);
26172 return this.gMapContext.circle;
26178 setPosition: function(location)
26180 this.gMapContext.location = location;
26181 this.gMapContext.marker.setPosition(location);
26182 this.gMapContext.map.panTo(location);
26183 this.drawCircle(location, this.gMapContext.radius, {});
26187 if (this.gMapContext.settings.enableReverseGeocode) {
26188 this.gMapContext.geodecoder.geocode({
26189 latLng: this.gMapContext.location
26190 }, function(results, status) {
26192 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26193 _this.gMapContext.locationName = results[0].formatted_address;
26194 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26196 _this.fireEvent('positionchanged', this, location);
26203 this.fireEvent('positionchanged', this, location);
26208 google.maps.event.trigger(this.gMapContext.map, "resize");
26210 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26212 this.fireEvent('resize', this);
26215 setPositionByLatLng: function(latitude, longitude)
26217 this.setPosition(new google.maps.LatLng(latitude, longitude));
26220 getCurrentPosition: function()
26223 latitude: this.gMapContext.location.lat(),
26224 longitude: this.gMapContext.location.lng()
26228 getAddressName: function()
26230 return this.gMapContext.locationName;
26233 getAddressComponents: function()
26235 return this.gMapContext.addressComponents;
26238 address_component_from_google_geocode: function(address_components)
26242 for (var i = 0; i < address_components.length; i++) {
26243 var component = address_components[i];
26244 if (component.types.indexOf("postal_code") >= 0) {
26245 result.postalCode = component.short_name;
26246 } else if (component.types.indexOf("street_number") >= 0) {
26247 result.streetNumber = component.short_name;
26248 } else if (component.types.indexOf("route") >= 0) {
26249 result.streetName = component.short_name;
26250 } else if (component.types.indexOf("neighborhood") >= 0) {
26251 result.city = component.short_name;
26252 } else if (component.types.indexOf("locality") >= 0) {
26253 result.city = component.short_name;
26254 } else if (component.types.indexOf("sublocality") >= 0) {
26255 result.district = component.short_name;
26256 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26257 result.stateOrProvince = component.short_name;
26258 } else if (component.types.indexOf("country") >= 0) {
26259 result.country = component.short_name;
26263 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26264 result.addressLine2 = "";
26268 setZoomLevel: function(zoom)
26270 this.gMapContext.map.setZoom(zoom);
26283 this.fireEvent('show', this);
26294 this.fireEvent('hide', this);
26299 Roo.apply(Roo.bootstrap.LocationPicker, {
26301 OverlayView : function(map, options)
26303 options = options || {};
26317 * @class Roo.bootstrap.Alert
26318 * @extends Roo.bootstrap.Component
26319 * Bootstrap Alert class
26320 * @cfg {String} title The title of alert
26321 * @cfg {String} html The content of alert
26322 * @cfg {String} weight ( success | info | warning | danger )
26323 * @cfg {String} faicon font-awesomeicon
26326 * Create a new alert
26327 * @param {Object} config The config object
26331 Roo.bootstrap.Alert = function(config){
26332 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26336 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26343 getAutoCreate : function()
26352 cls : 'roo-alert-icon'
26357 cls : 'roo-alert-title',
26362 cls : 'roo-alert-text',
26369 cfg.cn[0].cls += ' fa ' + this.faicon;
26373 cfg.cls += ' alert-' + this.weight;
26379 initEvents: function()
26381 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26384 setTitle : function(str)
26386 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26389 setText : function(str)
26391 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26394 setWeight : function(weight)
26397 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26400 this.weight = weight;
26402 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26405 setIcon : function(icon)
26408 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26411 this.faicon = icon;
26413 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26434 * @class Roo.bootstrap.UploadCropbox
26435 * @extends Roo.bootstrap.Component
26436 * Bootstrap UploadCropbox class
26437 * @cfg {String} emptyText show when image has been loaded
26438 * @cfg {String} rotateNotify show when image too small to rotate
26439 * @cfg {Number} errorTimeout default 3000
26440 * @cfg {Number} minWidth default 300
26441 * @cfg {Number} minHeight default 300
26442 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26443 * @cfg {Boolean} isDocument (true|false) default false
26444 * @cfg {String} url action url
26445 * @cfg {String} paramName default 'imageUpload'
26446 * @cfg {String} method default POST
26447 * @cfg {Boolean} loadMask (true|false) default true
26448 * @cfg {Boolean} loadingText default 'Loading...'
26451 * Create a new UploadCropbox
26452 * @param {Object} config The config object
26455 Roo.bootstrap.UploadCropbox = function(config){
26456 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26460 * @event beforeselectfile
26461 * Fire before select file
26462 * @param {Roo.bootstrap.UploadCropbox} this
26464 "beforeselectfile" : true,
26467 * Fire after initEvent
26468 * @param {Roo.bootstrap.UploadCropbox} this
26473 * Fire after initEvent
26474 * @param {Roo.bootstrap.UploadCropbox} this
26475 * @param {String} data
26480 * Fire when preparing the file data
26481 * @param {Roo.bootstrap.UploadCropbox} this
26482 * @param {Object} file
26487 * Fire when get exception
26488 * @param {Roo.bootstrap.UploadCropbox} this
26489 * @param {XMLHttpRequest} xhr
26491 "exception" : true,
26493 * @event beforeloadcanvas
26494 * Fire before load the canvas
26495 * @param {Roo.bootstrap.UploadCropbox} this
26496 * @param {String} src
26498 "beforeloadcanvas" : true,
26501 * Fire when trash image
26502 * @param {Roo.bootstrap.UploadCropbox} this
26507 * Fire when download the image
26508 * @param {Roo.bootstrap.UploadCropbox} this
26512 * @event footerbuttonclick
26513 * Fire when footerbuttonclick
26514 * @param {Roo.bootstrap.UploadCropbox} this
26515 * @param {String} type
26517 "footerbuttonclick" : true,
26521 * @param {Roo.bootstrap.UploadCropbox} this
26526 * Fire when rotate the image
26527 * @param {Roo.bootstrap.UploadCropbox} this
26528 * @param {String} pos
26533 * Fire when inspect the file
26534 * @param {Roo.bootstrap.UploadCropbox} this
26535 * @param {Object} file
26540 * Fire when xhr upload the file
26541 * @param {Roo.bootstrap.UploadCropbox} this
26542 * @param {Object} data
26547 * Fire when arrange the file data
26548 * @param {Roo.bootstrap.UploadCropbox} this
26549 * @param {Object} formData
26554 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26557 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26559 emptyText : 'Click to upload image',
26560 rotateNotify : 'Image is too small to rotate',
26561 errorTimeout : 3000,
26575 cropType : 'image/jpeg',
26577 canvasLoaded : false,
26578 isDocument : false,
26580 paramName : 'imageUpload',
26582 loadingText : 'Loading...',
26585 getAutoCreate : function()
26589 cls : 'roo-upload-cropbox',
26593 cls : 'roo-upload-cropbox-selector',
26598 cls : 'roo-upload-cropbox-body',
26599 style : 'cursor:pointer',
26603 cls : 'roo-upload-cropbox-preview'
26607 cls : 'roo-upload-cropbox-thumb'
26611 cls : 'roo-upload-cropbox-empty-notify',
26612 html : this.emptyText
26616 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26617 html : this.rotateNotify
26623 cls : 'roo-upload-cropbox-footer',
26626 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26636 onRender : function(ct, position)
26638 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26640 if (this.buttons.length) {
26642 Roo.each(this.buttons, function(bb) {
26644 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26646 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26652 this.maskEl = this.el;
26656 initEvents : function()
26658 this.urlAPI = (window.createObjectURL && window) ||
26659 (window.URL && URL.revokeObjectURL && URL) ||
26660 (window.webkitURL && webkitURL);
26662 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26663 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26665 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26666 this.selectorEl.hide();
26668 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26669 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26671 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26672 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26673 this.thumbEl.hide();
26675 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26676 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26678 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26679 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26680 this.errorEl.hide();
26682 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26683 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26684 this.footerEl.hide();
26686 this.setThumbBoxSize();
26692 this.fireEvent('initial', this);
26699 window.addEventListener("resize", function() { _this.resize(); } );
26701 this.bodyEl.on('click', this.beforeSelectFile, this);
26704 this.bodyEl.on('touchstart', this.onTouchStart, this);
26705 this.bodyEl.on('touchmove', this.onTouchMove, this);
26706 this.bodyEl.on('touchend', this.onTouchEnd, this);
26710 this.bodyEl.on('mousedown', this.onMouseDown, this);
26711 this.bodyEl.on('mousemove', this.onMouseMove, this);
26712 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26713 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26714 Roo.get(document).on('mouseup', this.onMouseUp, this);
26717 this.selectorEl.on('change', this.onFileSelected, this);
26723 this.baseScale = 1;
26725 this.baseRotate = 1;
26726 this.dragable = false;
26727 this.pinching = false;
26730 this.cropData = false;
26731 this.notifyEl.dom.innerHTML = this.emptyText;
26733 this.selectorEl.dom.value = '';
26737 resize : function()
26739 if(this.fireEvent('resize', this) != false){
26740 this.setThumbBoxPosition();
26741 this.setCanvasPosition();
26745 onFooterButtonClick : function(e, el, o, type)
26748 case 'rotate-left' :
26749 this.onRotateLeft(e);
26751 case 'rotate-right' :
26752 this.onRotateRight(e);
26755 this.beforeSelectFile(e);
26770 this.fireEvent('footerbuttonclick', this, type);
26773 beforeSelectFile : function(e)
26775 e.preventDefault();
26777 if(this.fireEvent('beforeselectfile', this) != false){
26778 this.selectorEl.dom.click();
26782 onFileSelected : function(e)
26784 e.preventDefault();
26786 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26790 var file = this.selectorEl.dom.files[0];
26792 if(this.fireEvent('inspect', this, file) != false){
26793 this.prepare(file);
26798 trash : function(e)
26800 this.fireEvent('trash', this);
26803 download : function(e)
26805 this.fireEvent('download', this);
26808 loadCanvas : function(src)
26810 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26814 this.imageEl = document.createElement('img');
26818 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26820 this.imageEl.src = src;
26824 onLoadCanvas : function()
26826 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26827 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26829 this.bodyEl.un('click', this.beforeSelectFile, this);
26831 this.notifyEl.hide();
26832 this.thumbEl.show();
26833 this.footerEl.show();
26835 this.baseRotateLevel();
26837 if(this.isDocument){
26838 this.setThumbBoxSize();
26841 this.setThumbBoxPosition();
26843 this.baseScaleLevel();
26849 this.canvasLoaded = true;
26852 this.maskEl.unmask();
26857 setCanvasPosition : function()
26859 if(!this.canvasEl){
26863 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26864 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26866 this.previewEl.setLeft(pw);
26867 this.previewEl.setTop(ph);
26871 onMouseDown : function(e)
26875 this.dragable = true;
26876 this.pinching = false;
26878 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26879 this.dragable = false;
26883 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26884 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26888 onMouseMove : function(e)
26892 if(!this.canvasLoaded){
26896 if (!this.dragable){
26900 var minX = Math.ceil(this.thumbEl.getLeft(true));
26901 var minY = Math.ceil(this.thumbEl.getTop(true));
26903 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26904 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26906 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26907 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26909 x = x - this.mouseX;
26910 y = y - this.mouseY;
26912 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26913 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26915 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26916 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26918 this.previewEl.setLeft(bgX);
26919 this.previewEl.setTop(bgY);
26921 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26922 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26925 onMouseUp : function(e)
26929 this.dragable = false;
26932 onMouseWheel : function(e)
26936 this.startScale = this.scale;
26938 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26940 if(!this.zoomable()){
26941 this.scale = this.startScale;
26950 zoomable : function()
26952 var minScale = this.thumbEl.getWidth() / this.minWidth;
26954 if(this.minWidth < this.minHeight){
26955 minScale = this.thumbEl.getHeight() / this.minHeight;
26958 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26959 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26963 (this.rotate == 0 || this.rotate == 180) &&
26965 width > this.imageEl.OriginWidth ||
26966 height > this.imageEl.OriginHeight ||
26967 (width < this.minWidth && height < this.minHeight)
26975 (this.rotate == 90 || this.rotate == 270) &&
26977 width > this.imageEl.OriginWidth ||
26978 height > this.imageEl.OriginHeight ||
26979 (width < this.minHeight && height < this.minWidth)
26986 !this.isDocument &&
26987 (this.rotate == 0 || this.rotate == 180) &&
26989 width < this.minWidth ||
26990 width > this.imageEl.OriginWidth ||
26991 height < this.minHeight ||
26992 height > this.imageEl.OriginHeight
26999 !this.isDocument &&
27000 (this.rotate == 90 || this.rotate == 270) &&
27002 width < this.minHeight ||
27003 width > this.imageEl.OriginWidth ||
27004 height < this.minWidth ||
27005 height > this.imageEl.OriginHeight
27015 onRotateLeft : function(e)
27017 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27019 var minScale = this.thumbEl.getWidth() / this.minWidth;
27021 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27022 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27024 this.startScale = this.scale;
27026 while (this.getScaleLevel() < minScale){
27028 this.scale = this.scale + 1;
27030 if(!this.zoomable()){
27035 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27036 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27041 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27048 this.scale = this.startScale;
27050 this.onRotateFail();
27055 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27057 if(this.isDocument){
27058 this.setThumbBoxSize();
27059 this.setThumbBoxPosition();
27060 this.setCanvasPosition();
27065 this.fireEvent('rotate', this, 'left');
27069 onRotateRight : function(e)
27071 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27073 var minScale = this.thumbEl.getWidth() / this.minWidth;
27075 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27076 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27078 this.startScale = this.scale;
27080 while (this.getScaleLevel() < minScale){
27082 this.scale = this.scale + 1;
27084 if(!this.zoomable()){
27089 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27090 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27095 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27102 this.scale = this.startScale;
27104 this.onRotateFail();
27109 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27111 if(this.isDocument){
27112 this.setThumbBoxSize();
27113 this.setThumbBoxPosition();
27114 this.setCanvasPosition();
27119 this.fireEvent('rotate', this, 'right');
27122 onRotateFail : function()
27124 this.errorEl.show(true);
27128 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27133 this.previewEl.dom.innerHTML = '';
27135 var canvasEl = document.createElement("canvas");
27137 var contextEl = canvasEl.getContext("2d");
27139 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27140 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27141 var center = this.imageEl.OriginWidth / 2;
27143 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27144 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27145 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27146 center = this.imageEl.OriginHeight / 2;
27149 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27151 contextEl.translate(center, center);
27152 contextEl.rotate(this.rotate * Math.PI / 180);
27154 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27156 this.canvasEl = document.createElement("canvas");
27158 this.contextEl = this.canvasEl.getContext("2d");
27160 switch (this.rotate) {
27163 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27164 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27166 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27171 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27172 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27174 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27175 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);
27179 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27184 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27185 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27187 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27188 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);
27192 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);
27197 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27198 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27200 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27201 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27205 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);
27212 this.previewEl.appendChild(this.canvasEl);
27214 this.setCanvasPosition();
27219 if(!this.canvasLoaded){
27223 var imageCanvas = document.createElement("canvas");
27225 var imageContext = imageCanvas.getContext("2d");
27227 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27228 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27230 var center = imageCanvas.width / 2;
27232 imageContext.translate(center, center);
27234 imageContext.rotate(this.rotate * Math.PI / 180);
27236 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27238 var canvas = document.createElement("canvas");
27240 var context = canvas.getContext("2d");
27242 canvas.width = this.minWidth;
27243 canvas.height = this.minHeight;
27245 switch (this.rotate) {
27248 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27249 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27251 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27252 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27254 var targetWidth = this.minWidth - 2 * x;
27255 var targetHeight = this.minHeight - 2 * y;
27259 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27260 scale = targetWidth / width;
27263 if(x > 0 && y == 0){
27264 scale = targetHeight / height;
27267 if(x > 0 && y > 0){
27268 scale = targetWidth / width;
27270 if(width < height){
27271 scale = targetHeight / height;
27275 context.scale(scale, scale);
27277 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27278 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27280 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27281 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27283 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27288 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27289 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27291 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27292 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27294 var targetWidth = this.minWidth - 2 * x;
27295 var targetHeight = this.minHeight - 2 * y;
27299 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27300 scale = targetWidth / width;
27303 if(x > 0 && y == 0){
27304 scale = targetHeight / height;
27307 if(x > 0 && y > 0){
27308 scale = targetWidth / width;
27310 if(width < height){
27311 scale = targetHeight / height;
27315 context.scale(scale, scale);
27317 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27318 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27320 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27321 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27323 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27325 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27330 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27331 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27333 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27334 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27336 var targetWidth = this.minWidth - 2 * x;
27337 var targetHeight = this.minHeight - 2 * y;
27341 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27342 scale = targetWidth / width;
27345 if(x > 0 && y == 0){
27346 scale = targetHeight / height;
27349 if(x > 0 && y > 0){
27350 scale = targetWidth / width;
27352 if(width < height){
27353 scale = targetHeight / height;
27357 context.scale(scale, scale);
27359 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27360 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27362 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27363 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27365 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27366 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27368 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27373 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27374 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27376 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27377 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27379 var targetWidth = this.minWidth - 2 * x;
27380 var targetHeight = this.minHeight - 2 * y;
27384 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27385 scale = targetWidth / width;
27388 if(x > 0 && y == 0){
27389 scale = targetHeight / height;
27392 if(x > 0 && y > 0){
27393 scale = targetWidth / width;
27395 if(width < height){
27396 scale = targetHeight / height;
27400 context.scale(scale, scale);
27402 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27403 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27405 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27406 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27408 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27410 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27417 this.cropData = canvas.toDataURL(this.cropType);
27419 if(this.fireEvent('crop', this, this.cropData) !== false){
27420 this.process(this.file, this.cropData);
27427 setThumbBoxSize : function()
27431 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27432 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27433 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27435 this.minWidth = width;
27436 this.minHeight = height;
27438 if(this.rotate == 90 || this.rotate == 270){
27439 this.minWidth = height;
27440 this.minHeight = width;
27445 width = Math.ceil(this.minWidth * height / this.minHeight);
27447 if(this.minWidth > this.minHeight){
27449 height = Math.ceil(this.minHeight * width / this.minWidth);
27452 this.thumbEl.setStyle({
27453 width : width + 'px',
27454 height : height + 'px'
27461 setThumbBoxPosition : function()
27463 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27464 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27466 this.thumbEl.setLeft(x);
27467 this.thumbEl.setTop(y);
27471 baseRotateLevel : function()
27473 this.baseRotate = 1;
27476 typeof(this.exif) != 'undefined' &&
27477 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27478 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27480 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27483 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27487 baseScaleLevel : function()
27491 if(this.isDocument){
27493 if(this.baseRotate == 6 || this.baseRotate == 8){
27495 height = this.thumbEl.getHeight();
27496 this.baseScale = height / this.imageEl.OriginWidth;
27498 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27499 width = this.thumbEl.getWidth();
27500 this.baseScale = width / this.imageEl.OriginHeight;
27506 height = this.thumbEl.getHeight();
27507 this.baseScale = height / this.imageEl.OriginHeight;
27509 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27510 width = this.thumbEl.getWidth();
27511 this.baseScale = width / this.imageEl.OriginWidth;
27517 if(this.baseRotate == 6 || this.baseRotate == 8){
27519 width = this.thumbEl.getHeight();
27520 this.baseScale = width / this.imageEl.OriginHeight;
27522 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27523 height = this.thumbEl.getWidth();
27524 this.baseScale = height / this.imageEl.OriginHeight;
27527 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27528 height = this.thumbEl.getWidth();
27529 this.baseScale = height / this.imageEl.OriginHeight;
27531 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27532 width = this.thumbEl.getHeight();
27533 this.baseScale = width / this.imageEl.OriginWidth;
27540 width = this.thumbEl.getWidth();
27541 this.baseScale = width / this.imageEl.OriginWidth;
27543 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27544 height = this.thumbEl.getHeight();
27545 this.baseScale = height / this.imageEl.OriginHeight;
27548 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27550 height = this.thumbEl.getHeight();
27551 this.baseScale = height / this.imageEl.OriginHeight;
27553 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27554 width = this.thumbEl.getWidth();
27555 this.baseScale = width / this.imageEl.OriginWidth;
27563 getScaleLevel : function()
27565 return this.baseScale * Math.pow(1.1, this.scale);
27568 onTouchStart : function(e)
27570 if(!this.canvasLoaded){
27571 this.beforeSelectFile(e);
27575 var touches = e.browserEvent.touches;
27581 if(touches.length == 1){
27582 this.onMouseDown(e);
27586 if(touches.length != 2){
27592 for(var i = 0, finger; finger = touches[i]; i++){
27593 coords.push(finger.pageX, finger.pageY);
27596 var x = Math.pow(coords[0] - coords[2], 2);
27597 var y = Math.pow(coords[1] - coords[3], 2);
27599 this.startDistance = Math.sqrt(x + y);
27601 this.startScale = this.scale;
27603 this.pinching = true;
27604 this.dragable = false;
27608 onTouchMove : function(e)
27610 if(!this.pinching && !this.dragable){
27614 var touches = e.browserEvent.touches;
27621 this.onMouseMove(e);
27627 for(var i = 0, finger; finger = touches[i]; i++){
27628 coords.push(finger.pageX, finger.pageY);
27631 var x = Math.pow(coords[0] - coords[2], 2);
27632 var y = Math.pow(coords[1] - coords[3], 2);
27634 this.endDistance = Math.sqrt(x + y);
27636 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27638 if(!this.zoomable()){
27639 this.scale = this.startScale;
27647 onTouchEnd : function(e)
27649 this.pinching = false;
27650 this.dragable = false;
27654 process : function(file, crop)
27657 this.maskEl.mask(this.loadingText);
27660 this.xhr = new XMLHttpRequest();
27662 file.xhr = this.xhr;
27664 this.xhr.open(this.method, this.url, true);
27667 "Accept": "application/json",
27668 "Cache-Control": "no-cache",
27669 "X-Requested-With": "XMLHttpRequest"
27672 for (var headerName in headers) {
27673 var headerValue = headers[headerName];
27675 this.xhr.setRequestHeader(headerName, headerValue);
27681 this.xhr.onload = function()
27683 _this.xhrOnLoad(_this.xhr);
27686 this.xhr.onerror = function()
27688 _this.xhrOnError(_this.xhr);
27691 var formData = new FormData();
27693 formData.append('returnHTML', 'NO');
27696 formData.append('crop', crop);
27699 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27700 formData.append(this.paramName, file, file.name);
27703 if(typeof(file.filename) != 'undefined'){
27704 formData.append('filename', file.filename);
27707 if(typeof(file.mimetype) != 'undefined'){
27708 formData.append('mimetype', file.mimetype);
27711 if(this.fireEvent('arrange', this, formData) != false){
27712 this.xhr.send(formData);
27716 xhrOnLoad : function(xhr)
27719 this.maskEl.unmask();
27722 if (xhr.readyState !== 4) {
27723 this.fireEvent('exception', this, xhr);
27727 var response = Roo.decode(xhr.responseText);
27729 if(!response.success){
27730 this.fireEvent('exception', this, xhr);
27734 var response = Roo.decode(xhr.responseText);
27736 this.fireEvent('upload', this, response);
27740 xhrOnError : function()
27743 this.maskEl.unmask();
27746 Roo.log('xhr on error');
27748 var response = Roo.decode(xhr.responseText);
27754 prepare : function(file)
27757 this.maskEl.mask(this.loadingText);
27763 if(typeof(file) === 'string'){
27764 this.loadCanvas(file);
27768 if(!file || !this.urlAPI){
27773 this.cropType = file.type;
27777 if(this.fireEvent('prepare', this, this.file) != false){
27779 var reader = new FileReader();
27781 reader.onload = function (e) {
27782 if (e.target.error) {
27783 Roo.log(e.target.error);
27787 var buffer = e.target.result,
27788 dataView = new DataView(buffer),
27790 maxOffset = dataView.byteLength - 4,
27794 if (dataView.getUint16(0) === 0xffd8) {
27795 while (offset < maxOffset) {
27796 markerBytes = dataView.getUint16(offset);
27798 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27799 markerLength = dataView.getUint16(offset + 2) + 2;
27800 if (offset + markerLength > dataView.byteLength) {
27801 Roo.log('Invalid meta data: Invalid segment size.');
27805 if(markerBytes == 0xffe1){
27806 _this.parseExifData(
27813 offset += markerLength;
27823 var url = _this.urlAPI.createObjectURL(_this.file);
27825 _this.loadCanvas(url);
27830 reader.readAsArrayBuffer(this.file);
27836 parseExifData : function(dataView, offset, length)
27838 var tiffOffset = offset + 10,
27842 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27843 // No Exif data, might be XMP data instead
27847 // Check for the ASCII code for "Exif" (0x45786966):
27848 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27849 // No Exif data, might be XMP data instead
27852 if (tiffOffset + 8 > dataView.byteLength) {
27853 Roo.log('Invalid Exif data: Invalid segment size.');
27856 // Check for the two null bytes:
27857 if (dataView.getUint16(offset + 8) !== 0x0000) {
27858 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27861 // Check the byte alignment:
27862 switch (dataView.getUint16(tiffOffset)) {
27864 littleEndian = true;
27867 littleEndian = false;
27870 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27873 // Check for the TIFF tag marker (0x002A):
27874 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27875 Roo.log('Invalid Exif data: Missing TIFF marker.');
27878 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27879 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27881 this.parseExifTags(
27884 tiffOffset + dirOffset,
27889 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27894 if (dirOffset + 6 > dataView.byteLength) {
27895 Roo.log('Invalid Exif data: Invalid directory offset.');
27898 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27899 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27900 if (dirEndOffset + 4 > dataView.byteLength) {
27901 Roo.log('Invalid Exif data: Invalid directory size.');
27904 for (i = 0; i < tagsNumber; i += 1) {
27908 dirOffset + 2 + 12 * i, // tag offset
27912 // Return the offset to the next directory:
27913 return dataView.getUint32(dirEndOffset, littleEndian);
27916 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27918 var tag = dataView.getUint16(offset, littleEndian);
27920 this.exif[tag] = this.getExifValue(
27924 dataView.getUint16(offset + 2, littleEndian), // tag type
27925 dataView.getUint32(offset + 4, littleEndian), // tag length
27930 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27932 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27941 Roo.log('Invalid Exif data: Invalid tag type.');
27945 tagSize = tagType.size * length;
27946 // Determine if the value is contained in the dataOffset bytes,
27947 // or if the value at the dataOffset is a pointer to the actual data:
27948 dataOffset = tagSize > 4 ?
27949 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27950 if (dataOffset + tagSize > dataView.byteLength) {
27951 Roo.log('Invalid Exif data: Invalid data offset.');
27954 if (length === 1) {
27955 return tagType.getValue(dataView, dataOffset, littleEndian);
27958 for (i = 0; i < length; i += 1) {
27959 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27962 if (tagType.ascii) {
27964 // Concatenate the chars:
27965 for (i = 0; i < values.length; i += 1) {
27967 // Ignore the terminating NULL byte(s):
27968 if (c === '\u0000') {
27980 Roo.apply(Roo.bootstrap.UploadCropbox, {
27982 'Orientation': 0x0112
27986 1: 0, //'top-left',
27988 3: 180, //'bottom-right',
27989 // 4: 'bottom-left',
27991 6: 90, //'right-top',
27992 // 7: 'right-bottom',
27993 8: 270 //'left-bottom'
27997 // byte, 8-bit unsigned int:
27999 getValue: function (dataView, dataOffset) {
28000 return dataView.getUint8(dataOffset);
28004 // ascii, 8-bit byte:
28006 getValue: function (dataView, dataOffset) {
28007 return String.fromCharCode(dataView.getUint8(dataOffset));
28012 // short, 16 bit int:
28014 getValue: function (dataView, dataOffset, littleEndian) {
28015 return dataView.getUint16(dataOffset, littleEndian);
28019 // long, 32 bit int:
28021 getValue: function (dataView, dataOffset, littleEndian) {
28022 return dataView.getUint32(dataOffset, littleEndian);
28026 // rational = two long values, first is numerator, second is denominator:
28028 getValue: function (dataView, dataOffset, littleEndian) {
28029 return dataView.getUint32(dataOffset, littleEndian) /
28030 dataView.getUint32(dataOffset + 4, littleEndian);
28034 // slong, 32 bit signed int:
28036 getValue: function (dataView, dataOffset, littleEndian) {
28037 return dataView.getInt32(dataOffset, littleEndian);
28041 // srational, two slongs, first is numerator, second is denominator:
28043 getValue: function (dataView, dataOffset, littleEndian) {
28044 return dataView.getInt32(dataOffset, littleEndian) /
28045 dataView.getInt32(dataOffset + 4, littleEndian);
28055 cls : 'btn-group roo-upload-cropbox-rotate-left',
28056 action : 'rotate-left',
28060 cls : 'btn btn-default',
28061 html : '<i class="fa fa-undo"></i>'
28067 cls : 'btn-group roo-upload-cropbox-picture',
28068 action : 'picture',
28072 cls : 'btn btn-default',
28073 html : '<i class="fa fa-picture-o"></i>'
28079 cls : 'btn-group roo-upload-cropbox-rotate-right',
28080 action : 'rotate-right',
28084 cls : 'btn btn-default',
28085 html : '<i class="fa fa-repeat"></i>'
28093 cls : 'btn-group roo-upload-cropbox-rotate-left',
28094 action : 'rotate-left',
28098 cls : 'btn btn-default',
28099 html : '<i class="fa fa-undo"></i>'
28105 cls : 'btn-group roo-upload-cropbox-download',
28106 action : 'download',
28110 cls : 'btn btn-default',
28111 html : '<i class="fa fa-download"></i>'
28117 cls : 'btn-group roo-upload-cropbox-crop',
28122 cls : 'btn btn-default',
28123 html : '<i class="fa fa-crop"></i>'
28129 cls : 'btn-group roo-upload-cropbox-trash',
28134 cls : 'btn btn-default',
28135 html : '<i class="fa fa-trash"></i>'
28141 cls : 'btn-group roo-upload-cropbox-rotate-right',
28142 action : 'rotate-right',
28146 cls : 'btn btn-default',
28147 html : '<i class="fa fa-repeat"></i>'
28155 cls : 'btn-group roo-upload-cropbox-rotate-left',
28156 action : 'rotate-left',
28160 cls : 'btn btn-default',
28161 html : '<i class="fa fa-undo"></i>'
28167 cls : 'btn-group roo-upload-cropbox-rotate-right',
28168 action : 'rotate-right',
28172 cls : 'btn btn-default',
28173 html : '<i class="fa fa-repeat"></i>'
28186 * @class Roo.bootstrap.DocumentManager
28187 * @extends Roo.bootstrap.Component
28188 * Bootstrap DocumentManager class
28189 * @cfg {String} paramName default 'imageUpload'
28190 * @cfg {String} toolTipName default 'filename'
28191 * @cfg {String} method default POST
28192 * @cfg {String} url action url
28193 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28194 * @cfg {Boolean} multiple multiple upload default true
28195 * @cfg {Number} thumbSize default 300
28196 * @cfg {String} fieldLabel
28197 * @cfg {Number} labelWidth default 4
28198 * @cfg {String} labelAlign (left|top) default left
28199 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28200 * @cfg {Number} labellg set the width of label (1-12)
28201 * @cfg {Number} labelmd set the width of label (1-12)
28202 * @cfg {Number} labelsm set the width of label (1-12)
28203 * @cfg {Number} labelxs set the width of label (1-12)
28206 * Create a new DocumentManager
28207 * @param {Object} config The config object
28210 Roo.bootstrap.DocumentManager = function(config){
28211 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28214 this.delegates = [];
28219 * Fire when initial the DocumentManager
28220 * @param {Roo.bootstrap.DocumentManager} this
28225 * inspect selected file
28226 * @param {Roo.bootstrap.DocumentManager} this
28227 * @param {File} file
28232 * Fire when xhr load exception
28233 * @param {Roo.bootstrap.DocumentManager} this
28234 * @param {XMLHttpRequest} xhr
28236 "exception" : true,
28238 * @event afterupload
28239 * Fire when xhr load exception
28240 * @param {Roo.bootstrap.DocumentManager} this
28241 * @param {XMLHttpRequest} xhr
28243 "afterupload" : true,
28246 * prepare the form data
28247 * @param {Roo.bootstrap.DocumentManager} this
28248 * @param {Object} formData
28253 * Fire when remove the file
28254 * @param {Roo.bootstrap.DocumentManager} this
28255 * @param {Object} file
28260 * Fire after refresh the file
28261 * @param {Roo.bootstrap.DocumentManager} this
28266 * Fire after click the image
28267 * @param {Roo.bootstrap.DocumentManager} this
28268 * @param {Object} file
28273 * Fire when upload a image and editable set to true
28274 * @param {Roo.bootstrap.DocumentManager} this
28275 * @param {Object} file
28279 * @event beforeselectfile
28280 * Fire before select file
28281 * @param {Roo.bootstrap.DocumentManager} this
28283 "beforeselectfile" : true,
28286 * Fire before process file
28287 * @param {Roo.bootstrap.DocumentManager} this
28288 * @param {Object} file
28295 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28304 paramName : 'imageUpload',
28305 toolTipName : 'filename',
28308 labelAlign : 'left',
28318 getAutoCreate : function()
28320 var managerWidget = {
28322 cls : 'roo-document-manager',
28326 cls : 'roo-document-manager-selector',
28331 cls : 'roo-document-manager-uploader',
28335 cls : 'roo-document-manager-upload-btn',
28336 html : '<i class="fa fa-plus"></i>'
28347 cls : 'column col-md-12',
28352 if(this.fieldLabel.length){
28357 cls : 'column col-md-12',
28358 html : this.fieldLabel
28362 cls : 'column col-md-12',
28367 if(this.labelAlign == 'left'){
28372 html : this.fieldLabel
28381 if(this.labelWidth > 12){
28382 content[0].style = "width: " + this.labelWidth + 'px';
28385 if(this.labelWidth < 13 && this.labelmd == 0){
28386 this.labelmd = this.labelWidth;
28389 if(this.labellg > 0){
28390 content[0].cls += ' col-lg-' + this.labellg;
28391 content[1].cls += ' col-lg-' + (12 - this.labellg);
28394 if(this.labelmd > 0){
28395 content[0].cls += ' col-md-' + this.labelmd;
28396 content[1].cls += ' col-md-' + (12 - this.labelmd);
28399 if(this.labelsm > 0){
28400 content[0].cls += ' col-sm-' + this.labelsm;
28401 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28404 if(this.labelxs > 0){
28405 content[0].cls += ' col-xs-' + this.labelxs;
28406 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28414 cls : 'row clearfix',
28422 initEvents : function()
28424 this.managerEl = this.el.select('.roo-document-manager', true).first();
28425 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28427 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28428 this.selectorEl.hide();
28431 this.selectorEl.attr('multiple', 'multiple');
28434 this.selectorEl.on('change', this.onFileSelected, this);
28436 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28437 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28439 this.uploader.on('click', this.onUploaderClick, this);
28441 this.renderProgressDialog();
28445 window.addEventListener("resize", function() { _this.refresh(); } );
28447 this.fireEvent('initial', this);
28450 renderProgressDialog : function()
28454 this.progressDialog = new Roo.bootstrap.Modal({
28455 cls : 'roo-document-manager-progress-dialog',
28456 allow_close : false,
28466 btnclick : function() {
28467 _this.uploadCancel();
28473 this.progressDialog.render(Roo.get(document.body));
28475 this.progress = new Roo.bootstrap.Progress({
28476 cls : 'roo-document-manager-progress',
28481 this.progress.render(this.progressDialog.getChildContainer());
28483 this.progressBar = new Roo.bootstrap.ProgressBar({
28484 cls : 'roo-document-manager-progress-bar',
28487 aria_valuemax : 12,
28491 this.progressBar.render(this.progress.getChildContainer());
28494 onUploaderClick : function(e)
28496 e.preventDefault();
28498 if(this.fireEvent('beforeselectfile', this) != false){
28499 this.selectorEl.dom.click();
28504 onFileSelected : function(e)
28506 e.preventDefault();
28508 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28512 Roo.each(this.selectorEl.dom.files, function(file){
28513 if(this.fireEvent('inspect', this, file) != false){
28514 this.files.push(file);
28524 this.selectorEl.dom.value = '';
28526 if(!this.files.length){
28530 if(this.boxes > 0 && this.files.length > this.boxes){
28531 this.files = this.files.slice(0, this.boxes);
28534 this.uploader.show();
28536 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28537 this.uploader.hide();
28546 Roo.each(this.files, function(file){
28548 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28549 var f = this.renderPreview(file);
28554 if(file.type.indexOf('image') != -1){
28555 this.delegates.push(
28557 _this.process(file);
28558 }).createDelegate(this)
28566 _this.process(file);
28567 }).createDelegate(this)
28572 this.files = files;
28574 this.delegates = this.delegates.concat(docs);
28576 if(!this.delegates.length){
28581 this.progressBar.aria_valuemax = this.delegates.length;
28588 arrange : function()
28590 if(!this.delegates.length){
28591 this.progressDialog.hide();
28596 var delegate = this.delegates.shift();
28598 this.progressDialog.show();
28600 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28602 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28607 refresh : function()
28609 this.uploader.show();
28611 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28612 this.uploader.hide();
28615 Roo.isTouch ? this.closable(false) : this.closable(true);
28617 this.fireEvent('refresh', this);
28620 onRemove : function(e, el, o)
28622 e.preventDefault();
28624 this.fireEvent('remove', this, o);
28628 remove : function(o)
28632 Roo.each(this.files, function(file){
28633 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28642 this.files = files;
28649 Roo.each(this.files, function(file){
28654 file.target.remove();
28663 onClick : function(e, el, o)
28665 e.preventDefault();
28667 this.fireEvent('click', this, o);
28671 closable : function(closable)
28673 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28675 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28687 xhrOnLoad : function(xhr)
28689 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28693 if (xhr.readyState !== 4) {
28695 this.fireEvent('exception', this, xhr);
28699 var response = Roo.decode(xhr.responseText);
28701 if(!response.success){
28703 this.fireEvent('exception', this, xhr);
28707 var file = this.renderPreview(response.data);
28709 this.files.push(file);
28713 this.fireEvent('afterupload', this, xhr);
28717 xhrOnError : function(xhr)
28719 Roo.log('xhr on error');
28721 var response = Roo.decode(xhr.responseText);
28728 process : function(file)
28730 if(this.fireEvent('process', this, file) !== false){
28731 if(this.editable && file.type.indexOf('image') != -1){
28732 this.fireEvent('edit', this, file);
28736 this.uploadStart(file, false);
28743 uploadStart : function(file, crop)
28745 this.xhr = new XMLHttpRequest();
28747 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28752 file.xhr = this.xhr;
28754 this.managerEl.createChild({
28756 cls : 'roo-document-manager-loading',
28760 tooltip : file.name,
28761 cls : 'roo-document-manager-thumb',
28762 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28768 this.xhr.open(this.method, this.url, true);
28771 "Accept": "application/json",
28772 "Cache-Control": "no-cache",
28773 "X-Requested-With": "XMLHttpRequest"
28776 for (var headerName in headers) {
28777 var headerValue = headers[headerName];
28779 this.xhr.setRequestHeader(headerName, headerValue);
28785 this.xhr.onload = function()
28787 _this.xhrOnLoad(_this.xhr);
28790 this.xhr.onerror = function()
28792 _this.xhrOnError(_this.xhr);
28795 var formData = new FormData();
28797 formData.append('returnHTML', 'NO');
28800 formData.append('crop', crop);
28803 formData.append(this.paramName, file, file.name);
28810 if(this.fireEvent('prepare', this, formData, options) != false){
28812 if(options.manually){
28816 this.xhr.send(formData);
28820 this.uploadCancel();
28823 uploadCancel : function()
28829 this.delegates = [];
28831 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28838 renderPreview : function(file)
28840 if(typeof(file.target) != 'undefined' && file.target){
28844 var previewEl = this.managerEl.createChild({
28846 cls : 'roo-document-manager-preview',
28850 tooltip : file[this.toolTipName],
28851 cls : 'roo-document-manager-thumb',
28852 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28857 html : '<i class="fa fa-times-circle"></i>'
28862 var close = previewEl.select('button.close', true).first();
28864 close.on('click', this.onRemove, this, file);
28866 file.target = previewEl;
28868 var image = previewEl.select('img', true).first();
28872 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28874 image.on('click', this.onClick, this, file);
28880 onPreviewLoad : function(file, image)
28882 if(typeof(file.target) == 'undefined' || !file.target){
28886 var width = image.dom.naturalWidth || image.dom.width;
28887 var height = image.dom.naturalHeight || image.dom.height;
28889 if(width > height){
28890 file.target.addClass('wide');
28894 file.target.addClass('tall');
28899 uploadFromSource : function(file, crop)
28901 this.xhr = new XMLHttpRequest();
28903 this.managerEl.createChild({
28905 cls : 'roo-document-manager-loading',
28909 tooltip : file.name,
28910 cls : 'roo-document-manager-thumb',
28911 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28917 this.xhr.open(this.method, this.url, true);
28920 "Accept": "application/json",
28921 "Cache-Control": "no-cache",
28922 "X-Requested-With": "XMLHttpRequest"
28925 for (var headerName in headers) {
28926 var headerValue = headers[headerName];
28928 this.xhr.setRequestHeader(headerName, headerValue);
28934 this.xhr.onload = function()
28936 _this.xhrOnLoad(_this.xhr);
28939 this.xhr.onerror = function()
28941 _this.xhrOnError(_this.xhr);
28944 var formData = new FormData();
28946 formData.append('returnHTML', 'NO');
28948 formData.append('crop', crop);
28950 if(typeof(file.filename) != 'undefined'){
28951 formData.append('filename', file.filename);
28954 if(typeof(file.mimetype) != 'undefined'){
28955 formData.append('mimetype', file.mimetype);
28960 if(this.fireEvent('prepare', this, formData) != false){
28961 this.xhr.send(formData);
28971 * @class Roo.bootstrap.DocumentViewer
28972 * @extends Roo.bootstrap.Component
28973 * Bootstrap DocumentViewer class
28974 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28975 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28978 * Create a new DocumentViewer
28979 * @param {Object} config The config object
28982 Roo.bootstrap.DocumentViewer = function(config){
28983 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28988 * Fire after initEvent
28989 * @param {Roo.bootstrap.DocumentViewer} this
28995 * @param {Roo.bootstrap.DocumentViewer} this
29000 * Fire after download button
29001 * @param {Roo.bootstrap.DocumentViewer} this
29006 * Fire after trash button
29007 * @param {Roo.bootstrap.DocumentViewer} this
29014 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29016 showDownload : true,
29020 getAutoCreate : function()
29024 cls : 'roo-document-viewer',
29028 cls : 'roo-document-viewer-body',
29032 cls : 'roo-document-viewer-thumb',
29036 cls : 'roo-document-viewer-image'
29044 cls : 'roo-document-viewer-footer',
29047 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29051 cls : 'btn-group roo-document-viewer-download',
29055 cls : 'btn btn-default',
29056 html : '<i class="fa fa-download"></i>'
29062 cls : 'btn-group roo-document-viewer-trash',
29066 cls : 'btn btn-default',
29067 html : '<i class="fa fa-trash"></i>'
29080 initEvents : function()
29082 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29083 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29085 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29086 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29088 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29089 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29091 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29092 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29094 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29095 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29097 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29098 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29100 this.bodyEl.on('click', this.onClick, this);
29101 this.downloadBtn.on('click', this.onDownload, this);
29102 this.trashBtn.on('click', this.onTrash, this);
29104 this.downloadBtn.hide();
29105 this.trashBtn.hide();
29107 if(this.showDownload){
29108 this.downloadBtn.show();
29111 if(this.showTrash){
29112 this.trashBtn.show();
29115 if(!this.showDownload && !this.showTrash) {
29116 this.footerEl.hide();
29121 initial : function()
29123 this.fireEvent('initial', this);
29127 onClick : function(e)
29129 e.preventDefault();
29131 this.fireEvent('click', this);
29134 onDownload : function(e)
29136 e.preventDefault();
29138 this.fireEvent('download', this);
29141 onTrash : function(e)
29143 e.preventDefault();
29145 this.fireEvent('trash', this);
29157 * @class Roo.bootstrap.NavProgressBar
29158 * @extends Roo.bootstrap.Component
29159 * Bootstrap NavProgressBar class
29162 * Create a new nav progress bar
29163 * @param {Object} config The config object
29166 Roo.bootstrap.NavProgressBar = function(config){
29167 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29169 this.bullets = this.bullets || [];
29171 // Roo.bootstrap.NavProgressBar.register(this);
29175 * Fires when the active item changes
29176 * @param {Roo.bootstrap.NavProgressBar} this
29177 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29178 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29185 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29190 getAutoCreate : function()
29192 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29196 cls : 'roo-navigation-bar-group',
29200 cls : 'roo-navigation-top-bar'
29204 cls : 'roo-navigation-bullets-bar',
29208 cls : 'roo-navigation-bar'
29215 cls : 'roo-navigation-bottom-bar'
29225 initEvents: function()
29230 onRender : function(ct, position)
29232 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29234 if(this.bullets.length){
29235 Roo.each(this.bullets, function(b){
29244 addItem : function(cfg)
29246 var item = new Roo.bootstrap.NavProgressItem(cfg);
29248 item.parentId = this.id;
29249 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29252 var top = new Roo.bootstrap.Element({
29254 cls : 'roo-navigation-bar-text'
29257 var bottom = new Roo.bootstrap.Element({
29259 cls : 'roo-navigation-bar-text'
29262 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29263 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29265 var topText = new Roo.bootstrap.Element({
29267 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29270 var bottomText = new Roo.bootstrap.Element({
29272 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29275 topText.onRender(top.el, null);
29276 bottomText.onRender(bottom.el, null);
29279 item.bottomEl = bottom;
29282 this.barItems.push(item);
29287 getActive : function()
29289 var active = false;
29291 Roo.each(this.barItems, function(v){
29293 if (!v.isActive()) {
29305 setActiveItem : function(item)
29309 Roo.each(this.barItems, function(v){
29310 if (v.rid == item.rid) {
29314 if (v.isActive()) {
29315 v.setActive(false);
29320 item.setActive(true);
29322 this.fireEvent('changed', this, item, prev);
29325 getBarItem: function(rid)
29329 Roo.each(this.barItems, function(e) {
29330 if (e.rid != rid) {
29341 indexOfItem : function(item)
29345 Roo.each(this.barItems, function(v, i){
29347 if (v.rid != item.rid) {
29358 setActiveNext : function()
29360 var i = this.indexOfItem(this.getActive());
29362 if (i > this.barItems.length) {
29366 this.setActiveItem(this.barItems[i+1]);
29369 setActivePrev : function()
29371 var i = this.indexOfItem(this.getActive());
29377 this.setActiveItem(this.barItems[i-1]);
29380 format : function()
29382 if(!this.barItems.length){
29386 var width = 100 / this.barItems.length;
29388 Roo.each(this.barItems, function(i){
29389 i.el.setStyle('width', width + '%');
29390 i.topEl.el.setStyle('width', width + '%');
29391 i.bottomEl.el.setStyle('width', width + '%');
29400 * Nav Progress Item
29405 * @class Roo.bootstrap.NavProgressItem
29406 * @extends Roo.bootstrap.Component
29407 * Bootstrap NavProgressItem class
29408 * @cfg {String} rid the reference id
29409 * @cfg {Boolean} active (true|false) Is item active default false
29410 * @cfg {Boolean} disabled (true|false) Is item active default false
29411 * @cfg {String} html
29412 * @cfg {String} position (top|bottom) text position default bottom
29413 * @cfg {String} icon show icon instead of number
29416 * Create a new NavProgressItem
29417 * @param {Object} config The config object
29419 Roo.bootstrap.NavProgressItem = function(config){
29420 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29425 * The raw click event for the entire grid.
29426 * @param {Roo.bootstrap.NavProgressItem} this
29427 * @param {Roo.EventObject} e
29434 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29440 position : 'bottom',
29443 getAutoCreate : function()
29445 var iconCls = 'roo-navigation-bar-item-icon';
29447 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29451 cls: 'roo-navigation-bar-item',
29461 cfg.cls += ' active';
29464 cfg.cls += ' disabled';
29470 disable : function()
29472 this.setDisabled(true);
29475 enable : function()
29477 this.setDisabled(false);
29480 initEvents: function()
29482 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29484 this.iconEl.on('click', this.onClick, this);
29487 onClick : function(e)
29489 e.preventDefault();
29495 if(this.fireEvent('click', this, e) === false){
29499 this.parent().setActiveItem(this);
29502 isActive: function ()
29504 return this.active;
29507 setActive : function(state)
29509 if(this.active == state){
29513 this.active = state;
29516 this.el.addClass('active');
29520 this.el.removeClass('active');
29525 setDisabled : function(state)
29527 if(this.disabled == state){
29531 this.disabled = state;
29534 this.el.addClass('disabled');
29538 this.el.removeClass('disabled');
29541 tooltipEl : function()
29543 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29556 * @class Roo.bootstrap.FieldLabel
29557 * @extends Roo.bootstrap.Component
29558 * Bootstrap FieldLabel class
29559 * @cfg {String} html contents of the element
29560 * @cfg {String} tag tag of the element default label
29561 * @cfg {String} cls class of the element
29562 * @cfg {String} target label target
29563 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29564 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29565 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29566 * @cfg {String} iconTooltip default "This field is required"
29569 * Create a new FieldLabel
29570 * @param {Object} config The config object
29573 Roo.bootstrap.FieldLabel = function(config){
29574 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29579 * Fires after the field has been marked as invalid.
29580 * @param {Roo.form.FieldLabel} this
29581 * @param {String} msg The validation message
29586 * Fires after the field has been validated with no errors.
29587 * @param {Roo.form.FieldLabel} this
29593 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29600 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29601 validClass : 'text-success fa fa-lg fa-check',
29602 iconTooltip : 'This field is required',
29604 getAutoCreate : function(){
29608 cls : 'roo-bootstrap-field-label ' + this.cls,
29614 tooltip : this.iconTooltip
29626 initEvents: function()
29628 Roo.bootstrap.Element.superclass.initEvents.call(this);
29630 this.iconEl = this.el.select('i', true).first();
29632 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29634 Roo.bootstrap.FieldLabel.register(this);
29638 * Mark this field as valid
29640 markValid : function()
29642 this.iconEl.show();
29644 this.iconEl.removeClass(this.invalidClass);
29646 this.iconEl.addClass(this.validClass);
29648 this.fireEvent('valid', this);
29652 * Mark this field as invalid
29653 * @param {String} msg The validation message
29655 markInvalid : function(msg)
29657 this.iconEl.show();
29659 this.iconEl.removeClass(this.validClass);
29661 this.iconEl.addClass(this.invalidClass);
29663 this.fireEvent('invalid', this, msg);
29669 Roo.apply(Roo.bootstrap.FieldLabel, {
29674 * register a FieldLabel Group
29675 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29677 register : function(label)
29679 if(this.groups.hasOwnProperty(label.target)){
29683 this.groups[label.target] = label;
29687 * fetch a FieldLabel Group based on the target
29688 * @param {string} target
29689 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29691 get: function(target) {
29692 if (typeof(this.groups[target]) == 'undefined') {
29696 return this.groups[target] ;
29705 * page DateSplitField.
29711 * @class Roo.bootstrap.DateSplitField
29712 * @extends Roo.bootstrap.Component
29713 * Bootstrap DateSplitField class
29714 * @cfg {string} fieldLabel - the label associated
29715 * @cfg {Number} labelWidth set the width of label (0-12)
29716 * @cfg {String} labelAlign (top|left)
29717 * @cfg {Boolean} dayAllowBlank (true|false) default false
29718 * @cfg {Boolean} monthAllowBlank (true|false) default false
29719 * @cfg {Boolean} yearAllowBlank (true|false) default false
29720 * @cfg {string} dayPlaceholder
29721 * @cfg {string} monthPlaceholder
29722 * @cfg {string} yearPlaceholder
29723 * @cfg {string} dayFormat default 'd'
29724 * @cfg {string} monthFormat default 'm'
29725 * @cfg {string} yearFormat default 'Y'
29726 * @cfg {Number} labellg set the width of label (1-12)
29727 * @cfg {Number} labelmd set the width of label (1-12)
29728 * @cfg {Number} labelsm set the width of label (1-12)
29729 * @cfg {Number} labelxs set the width of label (1-12)
29733 * Create a new DateSplitField
29734 * @param {Object} config The config object
29737 Roo.bootstrap.DateSplitField = function(config){
29738 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29744 * getting the data of years
29745 * @param {Roo.bootstrap.DateSplitField} this
29746 * @param {Object} years
29751 * getting the data of days
29752 * @param {Roo.bootstrap.DateSplitField} this
29753 * @param {Object} days
29758 * Fires after the field has been marked as invalid.
29759 * @param {Roo.form.Field} this
29760 * @param {String} msg The validation message
29765 * Fires after the field has been validated with no errors.
29766 * @param {Roo.form.Field} this
29772 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29775 labelAlign : 'top',
29777 dayAllowBlank : false,
29778 monthAllowBlank : false,
29779 yearAllowBlank : false,
29780 dayPlaceholder : '',
29781 monthPlaceholder : '',
29782 yearPlaceholder : '',
29786 isFormField : true,
29792 getAutoCreate : function()
29796 cls : 'row roo-date-split-field-group',
29801 cls : 'form-hidden-field roo-date-split-field-group-value',
29807 var labelCls = 'col-md-12';
29808 var contentCls = 'col-md-4';
29810 if(this.fieldLabel){
29814 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29818 html : this.fieldLabel
29823 if(this.labelAlign == 'left'){
29825 if(this.labelWidth > 12){
29826 label.style = "width: " + this.labelWidth + 'px';
29829 if(this.labelWidth < 13 && this.labelmd == 0){
29830 this.labelmd = this.labelWidth;
29833 if(this.labellg > 0){
29834 labelCls = ' col-lg-' + this.labellg;
29835 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29838 if(this.labelmd > 0){
29839 labelCls = ' col-md-' + this.labelmd;
29840 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29843 if(this.labelsm > 0){
29844 labelCls = ' col-sm-' + this.labelsm;
29845 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29848 if(this.labelxs > 0){
29849 labelCls = ' col-xs-' + this.labelxs;
29850 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29854 label.cls += ' ' + labelCls;
29856 cfg.cn.push(label);
29859 Roo.each(['day', 'month', 'year'], function(t){
29862 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29869 inputEl: function ()
29871 return this.el.select('.roo-date-split-field-group-value', true).first();
29874 onRender : function(ct, position)
29878 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29880 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29882 this.dayField = new Roo.bootstrap.ComboBox({
29883 allowBlank : this.dayAllowBlank,
29884 alwaysQuery : true,
29885 displayField : 'value',
29888 forceSelection : true,
29890 placeholder : this.dayPlaceholder,
29891 selectOnFocus : true,
29892 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29893 triggerAction : 'all',
29895 valueField : 'value',
29896 store : new Roo.data.SimpleStore({
29897 data : (function() {
29899 _this.fireEvent('days', _this, days);
29902 fields : [ 'value' ]
29905 select : function (_self, record, index)
29907 _this.setValue(_this.getValue());
29912 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29914 this.monthField = new Roo.bootstrap.MonthField({
29915 after : '<i class=\"fa fa-calendar\"></i>',
29916 allowBlank : this.monthAllowBlank,
29917 placeholder : this.monthPlaceholder,
29920 render : function (_self)
29922 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29923 e.preventDefault();
29927 select : function (_self, oldvalue, newvalue)
29929 _this.setValue(_this.getValue());
29934 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29936 this.yearField = new Roo.bootstrap.ComboBox({
29937 allowBlank : this.yearAllowBlank,
29938 alwaysQuery : true,
29939 displayField : 'value',
29942 forceSelection : true,
29944 placeholder : this.yearPlaceholder,
29945 selectOnFocus : true,
29946 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29947 triggerAction : 'all',
29949 valueField : 'value',
29950 store : new Roo.data.SimpleStore({
29951 data : (function() {
29953 _this.fireEvent('years', _this, years);
29956 fields : [ 'value' ]
29959 select : function (_self, record, index)
29961 _this.setValue(_this.getValue());
29966 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29969 setValue : function(v, format)
29971 this.inputEl.dom.value = v;
29973 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29975 var d = Date.parseDate(v, f);
29982 this.setDay(d.format(this.dayFormat));
29983 this.setMonth(d.format(this.monthFormat));
29984 this.setYear(d.format(this.yearFormat));
29991 setDay : function(v)
29993 this.dayField.setValue(v);
29994 this.inputEl.dom.value = this.getValue();
29999 setMonth : function(v)
30001 this.monthField.setValue(v, true);
30002 this.inputEl.dom.value = this.getValue();
30007 setYear : function(v)
30009 this.yearField.setValue(v);
30010 this.inputEl.dom.value = this.getValue();
30015 getDay : function()
30017 return this.dayField.getValue();
30020 getMonth : function()
30022 return this.monthField.getValue();
30025 getYear : function()
30027 return this.yearField.getValue();
30030 getValue : function()
30032 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30034 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30044 this.inputEl.dom.value = '';
30049 validate : function()
30051 var d = this.dayField.validate();
30052 var m = this.monthField.validate();
30053 var y = this.yearField.validate();
30058 (!this.dayAllowBlank && !d) ||
30059 (!this.monthAllowBlank && !m) ||
30060 (!this.yearAllowBlank && !y)
30065 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30074 this.markInvalid();
30079 markValid : function()
30082 var label = this.el.select('label', true).first();
30083 var icon = this.el.select('i.fa-star', true).first();
30089 this.fireEvent('valid', this);
30093 * Mark this field as invalid
30094 * @param {String} msg The validation message
30096 markInvalid : function(msg)
30099 var label = this.el.select('label', true).first();
30100 var icon = this.el.select('i.fa-star', true).first();
30102 if(label && !icon){
30103 this.el.select('.roo-date-split-field-label', true).createChild({
30105 cls : 'text-danger fa fa-lg fa-star',
30106 tooltip : 'This field is required',
30107 style : 'margin-right:5px;'
30111 this.fireEvent('invalid', this, msg);
30114 clearInvalid : function()
30116 var label = this.el.select('label', true).first();
30117 var icon = this.el.select('i.fa-star', true).first();
30123 this.fireEvent('valid', this);
30126 getName: function()
30136 * http://masonry.desandro.com
30138 * The idea is to render all the bricks based on vertical width...
30140 * The original code extends 'outlayer' - we might need to use that....
30146 * @class Roo.bootstrap.LayoutMasonry
30147 * @extends Roo.bootstrap.Component
30148 * Bootstrap Layout Masonry class
30151 * Create a new Element
30152 * @param {Object} config The config object
30155 Roo.bootstrap.LayoutMasonry = function(config){
30157 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30161 Roo.bootstrap.LayoutMasonry.register(this);
30167 * Fire after layout the items
30168 * @param {Roo.bootstrap.LayoutMasonry} this
30169 * @param {Roo.EventObject} e
30176 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30179 * @cfg {Boolean} isLayoutInstant = no animation?
30181 isLayoutInstant : false, // needed?
30184 * @cfg {Number} boxWidth width of the columns
30189 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30194 * @cfg {Number} padWidth padding below box..
30199 * @cfg {Number} gutter gutter width..
30204 * @cfg {Number} maxCols maximum number of columns
30210 * @cfg {Boolean} isAutoInitial defalut true
30212 isAutoInitial : true,
30217 * @cfg {Boolean} isHorizontal defalut false
30219 isHorizontal : false,
30221 currentSize : null,
30227 bricks: null, //CompositeElement
30231 _isLayoutInited : false,
30233 // isAlternative : false, // only use for vertical layout...
30236 * @cfg {Number} alternativePadWidth padding below box..
30238 alternativePadWidth : 50,
30240 selectedBrick : [],
30242 getAutoCreate : function(){
30244 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30248 cls: 'blog-masonary-wrapper ' + this.cls,
30250 cls : 'mas-boxes masonary'
30257 getChildContainer: function( )
30259 if (this.boxesEl) {
30260 return this.boxesEl;
30263 this.boxesEl = this.el.select('.mas-boxes').first();
30265 return this.boxesEl;
30269 initEvents : function()
30273 if(this.isAutoInitial){
30274 Roo.log('hook children rendered');
30275 this.on('childrenrendered', function() {
30276 Roo.log('children rendered');
30282 initial : function()
30284 this.selectedBrick = [];
30286 this.currentSize = this.el.getBox(true);
30288 Roo.EventManager.onWindowResize(this.resize, this);
30290 if(!this.isAutoInitial){
30298 //this.layout.defer(500,this);
30302 resize : function()
30304 var cs = this.el.getBox(true);
30307 this.currentSize.width == cs.width &&
30308 this.currentSize.x == cs.x &&
30309 this.currentSize.height == cs.height &&
30310 this.currentSize.y == cs.y
30312 Roo.log("no change in with or X or Y");
30316 this.currentSize = cs;
30322 layout : function()
30324 this._resetLayout();
30326 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30328 this.layoutItems( isInstant );
30330 this._isLayoutInited = true;
30332 this.fireEvent('layout', this);
30336 _resetLayout : function()
30338 if(this.isHorizontal){
30339 this.horizontalMeasureColumns();
30343 this.verticalMeasureColumns();
30347 verticalMeasureColumns : function()
30349 this.getContainerWidth();
30351 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30352 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30356 var boxWidth = this.boxWidth + this.padWidth;
30358 if(this.containerWidth < this.boxWidth){
30359 boxWidth = this.containerWidth
30362 var containerWidth = this.containerWidth;
30364 var cols = Math.floor(containerWidth / boxWidth);
30366 this.cols = Math.max( cols, 1 );
30368 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30370 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30372 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30374 this.colWidth = boxWidth + avail - this.padWidth;
30376 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30377 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30380 horizontalMeasureColumns : function()
30382 this.getContainerWidth();
30384 var boxWidth = this.boxWidth;
30386 if(this.containerWidth < boxWidth){
30387 boxWidth = this.containerWidth;
30390 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30392 this.el.setHeight(boxWidth);
30396 getContainerWidth : function()
30398 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30401 layoutItems : function( isInstant )
30403 Roo.log(this.bricks);
30405 var items = Roo.apply([], this.bricks);
30407 if(this.isHorizontal){
30408 this._horizontalLayoutItems( items , isInstant );
30412 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30413 // this._verticalAlternativeLayoutItems( items , isInstant );
30417 this._verticalLayoutItems( items , isInstant );
30421 _verticalLayoutItems : function ( items , isInstant)
30423 if ( !items || !items.length ) {
30428 ['xs', 'xs', 'xs', 'tall'],
30429 ['xs', 'xs', 'tall'],
30430 ['xs', 'xs', 'sm'],
30431 ['xs', 'xs', 'xs'],
30437 ['sm', 'xs', 'xs'],
30441 ['tall', 'xs', 'xs', 'xs'],
30442 ['tall', 'xs', 'xs'],
30454 Roo.each(items, function(item, k){
30456 switch (item.size) {
30457 // these layouts take up a full box,
30468 boxes.push([item]);
30491 var filterPattern = function(box, length)
30499 var pattern = box.slice(0, length);
30503 Roo.each(pattern, function(i){
30504 format.push(i.size);
30507 Roo.each(standard, function(s){
30509 if(String(s) != String(format)){
30518 if(!match && length == 1){
30523 filterPattern(box, length - 1);
30527 queue.push(pattern);
30529 box = box.slice(length, box.length);
30531 filterPattern(box, 4);
30537 Roo.each(boxes, function(box, k){
30543 if(box.length == 1){
30548 filterPattern(box, 4);
30552 this._processVerticalLayoutQueue( queue, isInstant );
30556 // _verticalAlternativeLayoutItems : function( items , isInstant )
30558 // if ( !items || !items.length ) {
30562 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30566 _horizontalLayoutItems : function ( items , isInstant)
30568 if ( !items || !items.length || items.length < 3) {
30574 var eItems = items.slice(0, 3);
30576 items = items.slice(3, items.length);
30579 ['xs', 'xs', 'xs', 'wide'],
30580 ['xs', 'xs', 'wide'],
30581 ['xs', 'xs', 'sm'],
30582 ['xs', 'xs', 'xs'],
30588 ['sm', 'xs', 'xs'],
30592 ['wide', 'xs', 'xs', 'xs'],
30593 ['wide', 'xs', 'xs'],
30606 Roo.each(items, function(item, k){
30608 switch (item.size) {
30619 boxes.push([item]);
30643 var filterPattern = function(box, length)
30651 var pattern = box.slice(0, length);
30655 Roo.each(pattern, function(i){
30656 format.push(i.size);
30659 Roo.each(standard, function(s){
30661 if(String(s) != String(format)){
30670 if(!match && length == 1){
30675 filterPattern(box, length - 1);
30679 queue.push(pattern);
30681 box = box.slice(length, box.length);
30683 filterPattern(box, 4);
30689 Roo.each(boxes, function(box, k){
30695 if(box.length == 1){
30700 filterPattern(box, 4);
30707 var pos = this.el.getBox(true);
30711 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30713 var hit_end = false;
30715 Roo.each(queue, function(box){
30719 Roo.each(box, function(b){
30721 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30731 Roo.each(box, function(b){
30733 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30736 mx = Math.max(mx, b.x);
30740 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30744 Roo.each(box, function(b){
30746 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30760 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30763 /** Sets position of item in DOM
30764 * @param {Element} item
30765 * @param {Number} x - horizontal position
30766 * @param {Number} y - vertical position
30767 * @param {Boolean} isInstant - disables transitions
30769 _processVerticalLayoutQueue : function( queue, isInstant )
30771 var pos = this.el.getBox(true);
30776 for (var i = 0; i < this.cols; i++){
30780 Roo.each(queue, function(box, k){
30782 var col = k % this.cols;
30784 Roo.each(box, function(b,kk){
30786 b.el.position('absolute');
30788 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30789 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30791 if(b.size == 'md-left' || b.size == 'md-right'){
30792 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30793 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30796 b.el.setWidth(width);
30797 b.el.setHeight(height);
30799 b.el.select('iframe',true).setSize(width,height);
30803 for (var i = 0; i < this.cols; i++){
30805 if(maxY[i] < maxY[col]){
30810 col = Math.min(col, i);
30814 x = pos.x + col * (this.colWidth + this.padWidth);
30818 var positions = [];
30820 switch (box.length){
30822 positions = this.getVerticalOneBoxColPositions(x, y, box);
30825 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30828 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30831 positions = this.getVerticalFourBoxColPositions(x, y, box);
30837 Roo.each(box, function(b,kk){
30839 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30841 var sz = b.el.getSize();
30843 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30851 for (var i = 0; i < this.cols; i++){
30852 mY = Math.max(mY, maxY[i]);
30855 this.el.setHeight(mY - pos.y);
30859 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30861 // var pos = this.el.getBox(true);
30864 // var maxX = pos.right;
30866 // var maxHeight = 0;
30868 // Roo.each(items, function(item, k){
30872 // item.el.position('absolute');
30874 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30876 // item.el.setWidth(width);
30878 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30880 // item.el.setHeight(height);
30883 // item.el.setXY([x, y], isInstant ? false : true);
30885 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30888 // y = y + height + this.alternativePadWidth;
30890 // maxHeight = maxHeight + height + this.alternativePadWidth;
30894 // this.el.setHeight(maxHeight);
30898 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30900 var pos = this.el.getBox(true);
30905 var maxX = pos.right;
30907 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30909 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30911 Roo.each(queue, function(box, k){
30913 Roo.each(box, function(b, kk){
30915 b.el.position('absolute');
30917 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30918 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30920 if(b.size == 'md-left' || b.size == 'md-right'){
30921 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30922 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30925 b.el.setWidth(width);
30926 b.el.setHeight(height);
30934 var positions = [];
30936 switch (box.length){
30938 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30941 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30944 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30947 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30953 Roo.each(box, function(b,kk){
30955 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30957 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30965 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30967 Roo.each(eItems, function(b,k){
30969 b.size = (k == 0) ? 'sm' : 'xs';
30970 b.x = (k == 0) ? 2 : 1;
30971 b.y = (k == 0) ? 2 : 1;
30973 b.el.position('absolute');
30975 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30977 b.el.setWidth(width);
30979 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30981 b.el.setHeight(height);
30985 var positions = [];
30988 x : maxX - this.unitWidth * 2 - this.gutter,
30993 x : maxX - this.unitWidth,
30994 y : minY + (this.unitWidth + this.gutter) * 2
30998 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31002 Roo.each(eItems, function(b,k){
31004 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31010 getVerticalOneBoxColPositions : function(x, y, box)
31014 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31016 if(box[0].size == 'md-left'){
31020 if(box[0].size == 'md-right'){
31025 x : x + (this.unitWidth + this.gutter) * rand,
31032 getVerticalTwoBoxColPositions : function(x, y, box)
31036 if(box[0].size == 'xs'){
31040 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31044 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31058 x : x + (this.unitWidth + this.gutter) * 2,
31059 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31066 getVerticalThreeBoxColPositions : function(x, y, box)
31070 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31078 x : x + (this.unitWidth + this.gutter) * 1,
31083 x : x + (this.unitWidth + this.gutter) * 2,
31091 if(box[0].size == 'xs' && box[1].size == 'xs'){
31100 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31104 x : x + (this.unitWidth + this.gutter) * 1,
31118 x : x + (this.unitWidth + this.gutter) * 2,
31123 x : x + (this.unitWidth + this.gutter) * 2,
31124 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31131 getVerticalFourBoxColPositions : function(x, y, box)
31135 if(box[0].size == 'xs'){
31144 y : y + (this.unitHeight + this.gutter) * 1
31149 y : y + (this.unitHeight + this.gutter) * 2
31153 x : x + (this.unitWidth + this.gutter) * 1,
31167 x : x + (this.unitWidth + this.gutter) * 2,
31172 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31173 y : y + (this.unitHeight + this.gutter) * 1
31177 x : x + (this.unitWidth + this.gutter) * 2,
31178 y : y + (this.unitWidth + this.gutter) * 2
31185 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31189 if(box[0].size == 'md-left'){
31191 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31198 if(box[0].size == 'md-right'){
31200 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31201 y : minY + (this.unitWidth + this.gutter) * 1
31207 var rand = Math.floor(Math.random() * (4 - box[0].y));
31210 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31211 y : minY + (this.unitWidth + this.gutter) * rand
31218 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31222 if(box[0].size == 'xs'){
31225 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31230 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31231 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31239 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31244 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31245 y : minY + (this.unitWidth + this.gutter) * 2
31252 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31256 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31259 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31264 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31265 y : minY + (this.unitWidth + this.gutter) * 1
31269 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31270 y : minY + (this.unitWidth + this.gutter) * 2
31277 if(box[0].size == 'xs' && box[1].size == 'xs'){
31280 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31285 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31290 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31291 y : minY + (this.unitWidth + this.gutter) * 1
31299 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31304 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31305 y : minY + (this.unitWidth + this.gutter) * 2
31309 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31310 y : minY + (this.unitWidth + this.gutter) * 2
31317 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31321 if(box[0].size == 'xs'){
31324 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31329 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31334 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),
31339 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31340 y : minY + (this.unitWidth + this.gutter) * 1
31348 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31353 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31354 y : minY + (this.unitWidth + this.gutter) * 2
31358 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31359 y : minY + (this.unitWidth + this.gutter) * 2
31363 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),
31364 y : minY + (this.unitWidth + this.gutter) * 2
31372 * remove a Masonry Brick
31373 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31375 removeBrick : function(brick_id)
31381 for (var i = 0; i<this.bricks.length; i++) {
31382 if (this.bricks[i].id == brick_id) {
31383 this.bricks.splice(i,1);
31384 this.el.dom.removeChild(Roo.get(brick_id).dom);
31391 * adds a Masonry Brick
31392 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31394 addBrick : function(cfg)
31396 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31397 //this.register(cn);
31398 cn.parentId = this.id;
31399 cn.onRender(this.el, null);
31404 * register a Masonry Brick
31405 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31408 register : function(brick)
31410 this.bricks.push(brick);
31411 brick.masonryId = this.id;
31415 * clear all the Masonry Brick
31417 clearAll : function()
31420 //this.getChildContainer().dom.innerHTML = "";
31421 this.el.dom.innerHTML = '';
31424 getSelected : function()
31426 if (!this.selectedBrick) {
31430 return this.selectedBrick;
31434 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31438 * register a Masonry Layout
31439 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31442 register : function(layout)
31444 this.groups[layout.id] = layout;
31447 * fetch a Masonry Layout based on the masonry layout ID
31448 * @param {string} the masonry layout to add
31449 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31452 get: function(layout_id) {
31453 if (typeof(this.groups[layout_id]) == 'undefined') {
31456 return this.groups[layout_id] ;
31468 * http://masonry.desandro.com
31470 * The idea is to render all the bricks based on vertical width...
31472 * The original code extends 'outlayer' - we might need to use that....
31478 * @class Roo.bootstrap.LayoutMasonryAuto
31479 * @extends Roo.bootstrap.Component
31480 * Bootstrap Layout Masonry class
31483 * Create a new Element
31484 * @param {Object} config The config object
31487 Roo.bootstrap.LayoutMasonryAuto = function(config){
31488 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31491 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31494 * @cfg {Boolean} isFitWidth - resize the width..
31496 isFitWidth : false, // options..
31498 * @cfg {Boolean} isOriginLeft = left align?
31500 isOriginLeft : true,
31502 * @cfg {Boolean} isOriginTop = top align?
31504 isOriginTop : false,
31506 * @cfg {Boolean} isLayoutInstant = no animation?
31508 isLayoutInstant : false, // needed?
31510 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31512 isResizingContainer : true,
31514 * @cfg {Number} columnWidth width of the columns
31520 * @cfg {Number} maxCols maximum number of columns
31525 * @cfg {Number} padHeight padding below box..
31531 * @cfg {Boolean} isAutoInitial defalut true
31534 isAutoInitial : true,
31540 initialColumnWidth : 0,
31541 currentSize : null,
31543 colYs : null, // array.
31550 bricks: null, //CompositeElement
31551 cols : 0, // array?
31552 // element : null, // wrapped now this.el
31553 _isLayoutInited : null,
31556 getAutoCreate : function(){
31560 cls: 'blog-masonary-wrapper ' + this.cls,
31562 cls : 'mas-boxes masonary'
31569 getChildContainer: function( )
31571 if (this.boxesEl) {
31572 return this.boxesEl;
31575 this.boxesEl = this.el.select('.mas-boxes').first();
31577 return this.boxesEl;
31581 initEvents : function()
31585 if(this.isAutoInitial){
31586 Roo.log('hook children rendered');
31587 this.on('childrenrendered', function() {
31588 Roo.log('children rendered');
31595 initial : function()
31597 this.reloadItems();
31599 this.currentSize = this.el.getBox(true);
31601 /// was window resize... - let's see if this works..
31602 Roo.EventManager.onWindowResize(this.resize, this);
31604 if(!this.isAutoInitial){
31609 this.layout.defer(500,this);
31612 reloadItems: function()
31614 this.bricks = this.el.select('.masonry-brick', true);
31616 this.bricks.each(function(b) {
31617 //Roo.log(b.getSize());
31618 if (!b.attr('originalwidth')) {
31619 b.attr('originalwidth', b.getSize().width);
31624 Roo.log(this.bricks.elements.length);
31627 resize : function()
31630 var cs = this.el.getBox(true);
31632 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31633 Roo.log("no change in with or X");
31636 this.currentSize = cs;
31640 layout : function()
31643 this._resetLayout();
31644 //this._manageStamps();
31646 // don't animate first layout
31647 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31648 this.layoutItems( isInstant );
31650 // flag for initalized
31651 this._isLayoutInited = true;
31654 layoutItems : function( isInstant )
31656 //var items = this._getItemsForLayout( this.items );
31657 // original code supports filtering layout items.. we just ignore it..
31659 this._layoutItems( this.bricks , isInstant );
31661 this._postLayout();
31663 _layoutItems : function ( items , isInstant)
31665 //this.fireEvent( 'layout', this, items );
31668 if ( !items || !items.elements.length ) {
31669 // no items, emit event with empty array
31674 items.each(function(item) {
31675 Roo.log("layout item");
31677 // get x/y object from method
31678 var position = this._getItemLayoutPosition( item );
31680 position.item = item;
31681 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31682 queue.push( position );
31685 this._processLayoutQueue( queue );
31687 /** Sets position of item in DOM
31688 * @param {Element} item
31689 * @param {Number} x - horizontal position
31690 * @param {Number} y - vertical position
31691 * @param {Boolean} isInstant - disables transitions
31693 _processLayoutQueue : function( queue )
31695 for ( var i=0, len = queue.length; i < len; i++ ) {
31696 var obj = queue[i];
31697 obj.item.position('absolute');
31698 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31704 * Any logic you want to do after each layout,
31705 * i.e. size the container
31707 _postLayout : function()
31709 this.resizeContainer();
31712 resizeContainer : function()
31714 if ( !this.isResizingContainer ) {
31717 var size = this._getContainerSize();
31719 this.el.setSize(size.width,size.height);
31720 this.boxesEl.setSize(size.width,size.height);
31726 _resetLayout : function()
31728 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31729 this.colWidth = this.el.getWidth();
31730 //this.gutter = this.el.getWidth();
31732 this.measureColumns();
31738 this.colYs.push( 0 );
31744 measureColumns : function()
31746 this.getContainerWidth();
31747 // if columnWidth is 0, default to outerWidth of first item
31748 if ( !this.columnWidth ) {
31749 var firstItem = this.bricks.first();
31750 Roo.log(firstItem);
31751 this.columnWidth = this.containerWidth;
31752 if (firstItem && firstItem.attr('originalwidth') ) {
31753 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31755 // columnWidth fall back to item of first element
31756 Roo.log("set column width?");
31757 this.initialColumnWidth = this.columnWidth ;
31759 // if first elem has no width, default to size of container
31764 if (this.initialColumnWidth) {
31765 this.columnWidth = this.initialColumnWidth;
31770 // column width is fixed at the top - however if container width get's smaller we should
31773 // this bit calcs how man columns..
31775 var columnWidth = this.columnWidth += this.gutter;
31777 // calculate columns
31778 var containerWidth = this.containerWidth + this.gutter;
31780 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31781 // fix rounding errors, typically with gutters
31782 var excess = columnWidth - containerWidth % columnWidth;
31785 // if overshoot is less than a pixel, round up, otherwise floor it
31786 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31787 cols = Math[ mathMethod ]( cols );
31788 this.cols = Math.max( cols, 1 );
31789 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31791 // padding positioning..
31792 var totalColWidth = this.cols * this.columnWidth;
31793 var padavail = this.containerWidth - totalColWidth;
31794 // so for 2 columns - we need 3 'pads'
31796 var padNeeded = (1+this.cols) * this.padWidth;
31798 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31800 this.columnWidth += padExtra
31801 //this.padWidth = Math.floor(padavail / ( this.cols));
31803 // adjust colum width so that padding is fixed??
31805 // we have 3 columns ... total = width * 3
31806 // we have X left over... that should be used by
31808 //if (this.expandC) {
31816 getContainerWidth : function()
31818 /* // container is parent if fit width
31819 var container = this.isFitWidth ? this.element.parentNode : this.element;
31820 // check that this.size and size are there
31821 // IE8 triggers resize on body size change, so they might not be
31823 var size = getSize( container ); //FIXME
31824 this.containerWidth = size && size.innerWidth; //FIXME
31827 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31831 _getItemLayoutPosition : function( item ) // what is item?
31833 // we resize the item to our columnWidth..
31835 item.setWidth(this.columnWidth);
31836 item.autoBoxAdjust = false;
31838 var sz = item.getSize();
31840 // how many columns does this brick span
31841 var remainder = this.containerWidth % this.columnWidth;
31843 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31844 // round if off by 1 pixel, otherwise use ceil
31845 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31846 colSpan = Math.min( colSpan, this.cols );
31848 // normally this should be '1' as we dont' currently allow multi width columns..
31850 var colGroup = this._getColGroup( colSpan );
31851 // get the minimum Y value from the columns
31852 var minimumY = Math.min.apply( Math, colGroup );
31853 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31855 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31857 // position the brick
31859 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31860 y: this.currentSize.y + minimumY + this.padHeight
31864 // apply setHeight to necessary columns
31865 var setHeight = minimumY + sz.height + this.padHeight;
31866 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31868 var setSpan = this.cols + 1 - colGroup.length;
31869 for ( var i = 0; i < setSpan; i++ ) {
31870 this.colYs[ shortColIndex + i ] = setHeight ;
31877 * @param {Number} colSpan - number of columns the element spans
31878 * @returns {Array} colGroup
31880 _getColGroup : function( colSpan )
31882 if ( colSpan < 2 ) {
31883 // if brick spans only one column, use all the column Ys
31888 // how many different places could this brick fit horizontally
31889 var groupCount = this.cols + 1 - colSpan;
31890 // for each group potential horizontal position
31891 for ( var i = 0; i < groupCount; i++ ) {
31892 // make an array of colY values for that one group
31893 var groupColYs = this.colYs.slice( i, i + colSpan );
31894 // and get the max value of the array
31895 colGroup[i] = Math.max.apply( Math, groupColYs );
31900 _manageStamp : function( stamp )
31902 var stampSize = stamp.getSize();
31903 var offset = stamp.getBox();
31904 // get the columns that this stamp affects
31905 var firstX = this.isOriginLeft ? offset.x : offset.right;
31906 var lastX = firstX + stampSize.width;
31907 var firstCol = Math.floor( firstX / this.columnWidth );
31908 firstCol = Math.max( 0, firstCol );
31910 var lastCol = Math.floor( lastX / this.columnWidth );
31911 // lastCol should not go over if multiple of columnWidth #425
31912 lastCol -= lastX % this.columnWidth ? 0 : 1;
31913 lastCol = Math.min( this.cols - 1, lastCol );
31915 // set colYs to bottom of the stamp
31916 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31919 for ( var i = firstCol; i <= lastCol; i++ ) {
31920 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31925 _getContainerSize : function()
31927 this.maxY = Math.max.apply( Math, this.colYs );
31932 if ( this.isFitWidth ) {
31933 size.width = this._getContainerFitWidth();
31939 _getContainerFitWidth : function()
31941 var unusedCols = 0;
31942 // count unused columns
31945 if ( this.colYs[i] !== 0 ) {
31950 // fit container to columns that have been used
31951 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31954 needsResizeLayout : function()
31956 var previousWidth = this.containerWidth;
31957 this.getContainerWidth();
31958 return previousWidth !== this.containerWidth;
31973 * @class Roo.bootstrap.MasonryBrick
31974 * @extends Roo.bootstrap.Component
31975 * Bootstrap MasonryBrick class
31978 * Create a new MasonryBrick
31979 * @param {Object} config The config object
31982 Roo.bootstrap.MasonryBrick = function(config){
31984 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31986 Roo.bootstrap.MasonryBrick.register(this);
31992 * When a MasonryBrick is clcik
31993 * @param {Roo.bootstrap.MasonryBrick} this
31994 * @param {Roo.EventObject} e
32000 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32003 * @cfg {String} title
32007 * @cfg {String} html
32011 * @cfg {String} bgimage
32015 * @cfg {String} videourl
32019 * @cfg {String} cls
32023 * @cfg {String} href
32027 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32032 * @cfg {String} placetitle (center|bottom)
32037 * @cfg {Boolean} isFitContainer defalut true
32039 isFitContainer : true,
32042 * @cfg {Boolean} preventDefault defalut false
32044 preventDefault : false,
32047 * @cfg {Boolean} inverse defalut false
32049 maskInverse : false,
32051 getAutoCreate : function()
32053 if(!this.isFitContainer){
32054 return this.getSplitAutoCreate();
32057 var cls = 'masonry-brick masonry-brick-full';
32059 if(this.href.length){
32060 cls += ' masonry-brick-link';
32063 if(this.bgimage.length){
32064 cls += ' masonry-brick-image';
32067 if(this.maskInverse){
32068 cls += ' mask-inverse';
32071 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32072 cls += ' enable-mask';
32076 cls += ' masonry-' + this.size + '-brick';
32079 if(this.placetitle.length){
32081 switch (this.placetitle) {
32083 cls += ' masonry-center-title';
32086 cls += ' masonry-bottom-title';
32093 if(!this.html.length && !this.bgimage.length){
32094 cls += ' masonry-center-title';
32097 if(!this.html.length && this.bgimage.length){
32098 cls += ' masonry-bottom-title';
32103 cls += ' ' + this.cls;
32107 tag: (this.href.length) ? 'a' : 'div',
32112 cls: 'masonry-brick-mask'
32116 cls: 'masonry-brick-paragraph',
32122 if(this.href.length){
32123 cfg.href = this.href;
32126 var cn = cfg.cn[1].cn;
32128 if(this.title.length){
32131 cls: 'masonry-brick-title',
32136 if(this.html.length){
32139 cls: 'masonry-brick-text',
32144 if (!this.title.length && !this.html.length) {
32145 cfg.cn[1].cls += ' hide';
32148 if(this.bgimage.length){
32151 cls: 'masonry-brick-image-view',
32156 if(this.videourl.length){
32157 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32158 // youtube support only?
32161 cls: 'masonry-brick-image-view',
32164 allowfullscreen : true
32172 getSplitAutoCreate : function()
32174 var cls = 'masonry-brick masonry-brick-split';
32176 if(this.href.length){
32177 cls += ' masonry-brick-link';
32180 if(this.bgimage.length){
32181 cls += ' masonry-brick-image';
32185 cls += ' masonry-' + this.size + '-brick';
32188 switch (this.placetitle) {
32190 cls += ' masonry-center-title';
32193 cls += ' masonry-bottom-title';
32196 if(!this.bgimage.length){
32197 cls += ' masonry-center-title';
32200 if(this.bgimage.length){
32201 cls += ' masonry-bottom-title';
32207 cls += ' ' + this.cls;
32211 tag: (this.href.length) ? 'a' : 'div',
32216 cls: 'masonry-brick-split-head',
32220 cls: 'masonry-brick-paragraph',
32227 cls: 'masonry-brick-split-body',
32233 if(this.href.length){
32234 cfg.href = this.href;
32237 if(this.title.length){
32238 cfg.cn[0].cn[0].cn.push({
32240 cls: 'masonry-brick-title',
32245 if(this.html.length){
32246 cfg.cn[1].cn.push({
32248 cls: 'masonry-brick-text',
32253 if(this.bgimage.length){
32254 cfg.cn[0].cn.push({
32256 cls: 'masonry-brick-image-view',
32261 if(this.videourl.length){
32262 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32263 // youtube support only?
32264 cfg.cn[0].cn.cn.push({
32266 cls: 'masonry-brick-image-view',
32269 allowfullscreen : true
32276 initEvents: function()
32278 switch (this.size) {
32311 this.el.on('touchstart', this.onTouchStart, this);
32312 this.el.on('touchmove', this.onTouchMove, this);
32313 this.el.on('touchend', this.onTouchEnd, this);
32314 this.el.on('contextmenu', this.onContextMenu, this);
32316 this.el.on('mouseenter' ,this.enter, this);
32317 this.el.on('mouseleave', this.leave, this);
32318 this.el.on('click', this.onClick, this);
32321 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32322 this.parent().bricks.push(this);
32327 onClick: function(e, el)
32329 var time = this.endTimer - this.startTimer;
32330 // Roo.log(e.preventDefault());
32333 e.preventDefault();
32338 if(!this.preventDefault){
32342 e.preventDefault();
32344 if (this.activcClass != '') {
32345 this.selectBrick();
32348 this.fireEvent('click', this);
32351 enter: function(e, el)
32353 e.preventDefault();
32355 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32359 if(this.bgimage.length && this.html.length){
32360 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32364 leave: function(e, el)
32366 e.preventDefault();
32368 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32372 if(this.bgimage.length && this.html.length){
32373 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32377 onTouchStart: function(e, el)
32379 // e.preventDefault();
32381 this.touchmoved = false;
32383 if(!this.isFitContainer){
32387 if(!this.bgimage.length || !this.html.length){
32391 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32393 this.timer = new Date().getTime();
32397 onTouchMove: function(e, el)
32399 this.touchmoved = true;
32402 onContextMenu : function(e,el)
32404 e.preventDefault();
32405 e.stopPropagation();
32409 onTouchEnd: function(e, el)
32411 // e.preventDefault();
32413 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32420 if(!this.bgimage.length || !this.html.length){
32422 if(this.href.length){
32423 window.location.href = this.href;
32429 if(!this.isFitContainer){
32433 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32435 window.location.href = this.href;
32438 //selection on single brick only
32439 selectBrick : function() {
32441 if (!this.parentId) {
32445 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32446 var index = m.selectedBrick.indexOf(this.id);
32449 m.selectedBrick.splice(index,1);
32450 this.el.removeClass(this.activeClass);
32454 for(var i = 0; i < m.selectedBrick.length; i++) {
32455 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32456 b.el.removeClass(b.activeClass);
32459 m.selectedBrick = [];
32461 m.selectedBrick.push(this.id);
32462 this.el.addClass(this.activeClass);
32468 Roo.apply(Roo.bootstrap.MasonryBrick, {
32471 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32473 * register a Masonry Brick
32474 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32477 register : function(brick)
32479 //this.groups[brick.id] = brick;
32480 this.groups.add(brick.id, brick);
32483 * fetch a masonry brick based on the masonry brick ID
32484 * @param {string} the masonry brick to add
32485 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32488 get: function(brick_id)
32490 // if (typeof(this.groups[brick_id]) == 'undefined') {
32493 // return this.groups[brick_id] ;
32495 if(this.groups.key(brick_id)) {
32496 return this.groups.key(brick_id);
32514 * @class Roo.bootstrap.Brick
32515 * @extends Roo.bootstrap.Component
32516 * Bootstrap Brick class
32519 * Create a new Brick
32520 * @param {Object} config The config object
32523 Roo.bootstrap.Brick = function(config){
32524 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32530 * When a Brick is click
32531 * @param {Roo.bootstrap.Brick} this
32532 * @param {Roo.EventObject} e
32538 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32541 * @cfg {String} title
32545 * @cfg {String} html
32549 * @cfg {String} bgimage
32553 * @cfg {String} cls
32557 * @cfg {String} href
32561 * @cfg {String} video
32565 * @cfg {Boolean} square
32569 getAutoCreate : function()
32571 var cls = 'roo-brick';
32573 if(this.href.length){
32574 cls += ' roo-brick-link';
32577 if(this.bgimage.length){
32578 cls += ' roo-brick-image';
32581 if(!this.html.length && !this.bgimage.length){
32582 cls += ' roo-brick-center-title';
32585 if(!this.html.length && this.bgimage.length){
32586 cls += ' roo-brick-bottom-title';
32590 cls += ' ' + this.cls;
32594 tag: (this.href.length) ? 'a' : 'div',
32599 cls: 'roo-brick-paragraph',
32605 if(this.href.length){
32606 cfg.href = this.href;
32609 var cn = cfg.cn[0].cn;
32611 if(this.title.length){
32614 cls: 'roo-brick-title',
32619 if(this.html.length){
32622 cls: 'roo-brick-text',
32629 if(this.bgimage.length){
32632 cls: 'roo-brick-image-view',
32640 initEvents: function()
32642 if(this.title.length || this.html.length){
32643 this.el.on('mouseenter' ,this.enter, this);
32644 this.el.on('mouseleave', this.leave, this);
32647 Roo.EventManager.onWindowResize(this.resize, this);
32649 if(this.bgimage.length){
32650 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32651 this.imageEl.on('load', this.onImageLoad, this);
32658 onImageLoad : function()
32663 resize : function()
32665 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32667 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32669 if(this.bgimage.length){
32670 var image = this.el.select('.roo-brick-image-view', true).first();
32672 image.setWidth(paragraph.getWidth());
32675 image.setHeight(paragraph.getWidth());
32678 this.el.setHeight(image.getHeight());
32679 paragraph.setHeight(image.getHeight());
32685 enter: function(e, el)
32687 e.preventDefault();
32689 if(this.bgimage.length){
32690 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32691 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32695 leave: function(e, el)
32697 e.preventDefault();
32699 if(this.bgimage.length){
32700 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32701 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32717 * @class Roo.bootstrap.NumberField
32718 * @extends Roo.bootstrap.Input
32719 * Bootstrap NumberField class
32725 * Create a new NumberField
32726 * @param {Object} config The config object
32729 Roo.bootstrap.NumberField = function(config){
32730 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32733 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32736 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32738 allowDecimals : true,
32740 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32742 decimalSeparator : ".",
32744 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32746 decimalPrecision : 2,
32748 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32750 allowNegative : true,
32752 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32754 minValue : Number.NEGATIVE_INFINITY,
32756 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32758 maxValue : Number.MAX_VALUE,
32760 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32762 minText : "The minimum value for this field is {0}",
32764 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32766 maxText : "The maximum value for this field is {0}",
32768 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32769 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32771 nanText : "{0} is not a valid number",
32773 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32778 initEvents : function()
32780 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32782 var allowed = "0123456789";
32784 if(this.allowDecimals){
32785 allowed += this.decimalSeparator;
32788 if(this.allowNegative){
32792 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32794 var keyPress = function(e){
32796 var k = e.getKey();
32798 var c = e.getCharCode();
32801 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32802 allowed.indexOf(String.fromCharCode(c)) === -1
32808 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32812 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32817 this.el.on("keypress", keyPress, this);
32820 validateValue : function(value)
32823 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32827 var num = this.parseValue(value);
32830 this.markInvalid(String.format(this.nanText, value));
32834 if(num < this.minValue){
32835 this.markInvalid(String.format(this.minText, this.minValue));
32839 if(num > this.maxValue){
32840 this.markInvalid(String.format(this.maxText, this.maxValue));
32847 getValue : function()
32849 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32852 parseValue : function(value)
32854 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32855 return isNaN(value) ? '' : value;
32858 fixPrecision : function(value)
32860 var nan = isNaN(value);
32862 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32863 return nan ? '' : value;
32865 return parseFloat(value).toFixed(this.decimalPrecision);
32868 setValue : function(v)
32870 v = this.fixPrecision(v);
32871 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32874 decimalPrecisionFcn : function(v)
32876 return Math.floor(v);
32879 beforeBlur : function()
32885 var v = this.parseValue(this.getRawValue());
32900 * @class Roo.bootstrap.DocumentSlider
32901 * @extends Roo.bootstrap.Component
32902 * Bootstrap DocumentSlider class
32905 * Create a new DocumentViewer
32906 * @param {Object} config The config object
32909 Roo.bootstrap.DocumentSlider = function(config){
32910 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32917 * Fire after initEvent
32918 * @param {Roo.bootstrap.DocumentSlider} this
32923 * Fire after update
32924 * @param {Roo.bootstrap.DocumentSlider} this
32930 * @param {Roo.bootstrap.DocumentSlider} this
32936 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32942 getAutoCreate : function()
32946 cls : 'roo-document-slider',
32950 cls : 'roo-document-slider-header',
32954 cls : 'roo-document-slider-header-title'
32960 cls : 'roo-document-slider-body',
32964 cls : 'roo-document-slider-prev',
32968 cls : 'fa fa-chevron-left'
32974 cls : 'roo-document-slider-thumb',
32978 cls : 'roo-document-slider-image'
32984 cls : 'roo-document-slider-next',
32988 cls : 'fa fa-chevron-right'
33000 initEvents : function()
33002 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33003 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33005 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33006 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33008 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33009 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33011 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33012 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33014 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33015 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33017 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33018 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33020 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33021 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33023 this.thumbEl.on('click', this.onClick, this);
33025 this.prevIndicator.on('click', this.prev, this);
33027 this.nextIndicator.on('click', this.next, this);
33031 initial : function()
33033 if(this.files.length){
33034 this.indicator = 1;
33038 this.fireEvent('initial', this);
33041 update : function()
33043 this.imageEl.attr('src', this.files[this.indicator - 1]);
33045 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33047 this.prevIndicator.show();
33049 if(this.indicator == 1){
33050 this.prevIndicator.hide();
33053 this.nextIndicator.show();
33055 if(this.indicator == this.files.length){
33056 this.nextIndicator.hide();
33059 this.thumbEl.scrollTo('top');
33061 this.fireEvent('update', this);
33064 onClick : function(e)
33066 e.preventDefault();
33068 this.fireEvent('click', this);
33073 e.preventDefault();
33075 this.indicator = Math.max(1, this.indicator - 1);
33082 e.preventDefault();
33084 this.indicator = Math.min(this.files.length, this.indicator + 1);
33098 * @class Roo.bootstrap.RadioSet
33099 * @extends Roo.bootstrap.Input
33100 * Bootstrap RadioSet class
33101 * @cfg {String} indicatorpos (left|right) default left
33102 * @cfg {Boolean} inline (true|false) inline the element (default true)
33103 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33105 * Create a new RadioSet
33106 * @param {Object} config The config object
33109 Roo.bootstrap.RadioSet = function(config){
33111 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33115 Roo.bootstrap.RadioSet.register(this);
33120 * Fires when the element is checked or unchecked.
33121 * @param {Roo.bootstrap.RadioSet} this This radio
33122 * @param {Roo.bootstrap.Radio} item The checked item
33129 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33137 indicatorpos : 'left',
33139 getAutoCreate : function()
33143 cls : 'roo-radio-set-label',
33147 html : this.fieldLabel
33152 if(this.indicatorpos == 'left'){
33155 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33156 tooltip : 'This field is required'
33161 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33162 tooltip : 'This field is required'
33168 cls : 'roo-radio-set-items'
33171 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33173 if (align === 'left' && this.fieldLabel.length) {
33176 cls : "roo-radio-set-right",
33182 if(this.labelWidth > 12){
33183 label.style = "width: " + this.labelWidth + 'px';
33186 if(this.labelWidth < 13 && this.labelmd == 0){
33187 this.labelmd = this.labelWidth;
33190 if(this.labellg > 0){
33191 label.cls += ' col-lg-' + this.labellg;
33192 items.cls += ' col-lg-' + (12 - this.labellg);
33195 if(this.labelmd > 0){
33196 label.cls += ' col-md-' + this.labelmd;
33197 items.cls += ' col-md-' + (12 - this.labelmd);
33200 if(this.labelsm > 0){
33201 label.cls += ' col-sm-' + this.labelsm;
33202 items.cls += ' col-sm-' + (12 - this.labelsm);
33205 if(this.labelxs > 0){
33206 label.cls += ' col-xs-' + this.labelxs;
33207 items.cls += ' col-xs-' + (12 - this.labelxs);
33213 cls : 'roo-radio-set',
33217 cls : 'roo-radio-set-input',
33220 value : this.value ? this.value : ''
33227 if(this.weight.length){
33228 cfg.cls += ' roo-radio-' + this.weight;
33232 cfg.cls += ' roo-radio-set-inline';
33239 initEvents : function()
33241 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33242 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33244 if(!this.fieldLabel.length){
33245 this.labelEl.hide();
33248 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33249 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33251 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
33252 this.indicatorEl().hide();
33254 this.originalValue = this.getValue();
33258 inputEl: function ()
33260 return this.el.select('.roo-radio-set-input', true).first();
33263 getChildContainer : function()
33265 return this.itemsEl;
33268 register : function(item)
33270 this.radioes.push(item);
33274 validate : function()
33278 Roo.each(this.radioes, function(i){
33287 if(this.allowBlank) {
33291 if(this.disabled || valid){
33296 this.markInvalid();
33301 markValid : function()
33303 if(this.labelEl.isVisible(true)){
33304 this.indicatorEl().hide();
33307 this.el.removeClass([this.invalidClass, this.validClass]);
33308 this.el.addClass(this.validClass);
33310 this.fireEvent('valid', this);
33313 markInvalid : function(msg)
33315 if(this.allowBlank || this.disabled){
33319 if(this.labelEl.isVisible(true)){
33320 this.indicatorEl().show();
33323 this.el.removeClass([this.invalidClass, this.validClass]);
33324 this.el.addClass(this.invalidClass);
33326 this.fireEvent('invalid', this, msg);
33330 setValue : function(v, suppressEvent)
33334 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33337 Roo.each(this.radioes, function(i){
33340 i.el.removeClass('checked');
33342 if(i.value === v || i.value.toString() === v.toString()){
33344 i.el.addClass('checked');
33346 if(suppressEvent !== true){
33347 this.fireEvent('check', this, i);
33356 clearInvalid : function(){
33358 if(!this.el || this.preventMark){
33362 this.el.removeClass([this.invalidClass]);
33364 this.fireEvent('valid', this);
33369 Roo.apply(Roo.bootstrap.RadioSet, {
33373 register : function(set)
33375 this.groups[set.name] = set;
33378 get: function(name)
33380 if (typeof(this.groups[name]) == 'undefined') {
33384 return this.groups[name] ;
33390 * Ext JS Library 1.1.1
33391 * Copyright(c) 2006-2007, Ext JS, LLC.
33393 * Originally Released Under LGPL - original licence link has changed is not relivant.
33396 * <script type="text/javascript">
33401 * @class Roo.bootstrap.SplitBar
33402 * @extends Roo.util.Observable
33403 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33407 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33408 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33409 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33410 split.minSize = 100;
33411 split.maxSize = 600;
33412 split.animate = true;
33413 split.on('moved', splitterMoved);
33416 * Create a new SplitBar
33417 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33418 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33419 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33420 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33421 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33422 position of the SplitBar).
33424 Roo.bootstrap.SplitBar = function(cfg){
33429 // dragElement : elm
33430 // resizingElement: el,
33432 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33433 // placement : Roo.bootstrap.SplitBar.LEFT ,
33434 // existingProxy ???
33437 this.el = Roo.get(cfg.dragElement, true);
33438 this.el.dom.unselectable = "on";
33440 this.resizingEl = Roo.get(cfg.resizingElement, true);
33444 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33445 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33448 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33451 * The minimum size of the resizing element. (Defaults to 0)
33457 * The maximum size of the resizing element. (Defaults to 2000)
33460 this.maxSize = 2000;
33463 * Whether to animate the transition to the new size
33466 this.animate = false;
33469 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33472 this.useShim = false;
33477 if(!cfg.existingProxy){
33479 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33481 this.proxy = Roo.get(cfg.existingProxy).dom;
33484 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33487 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33490 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33493 this.dragSpecs = {};
33496 * @private The adapter to use to positon and resize elements
33498 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33499 this.adapter.init(this);
33501 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33503 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33504 this.el.addClass("roo-splitbar-h");
33507 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33508 this.el.addClass("roo-splitbar-v");
33514 * Fires when the splitter is moved (alias for {@link #event-moved})
33515 * @param {Roo.bootstrap.SplitBar} this
33516 * @param {Number} newSize the new width or height
33521 * Fires when the splitter is moved
33522 * @param {Roo.bootstrap.SplitBar} this
33523 * @param {Number} newSize the new width or height
33527 * @event beforeresize
33528 * Fires before the splitter is dragged
33529 * @param {Roo.bootstrap.SplitBar} this
33531 "beforeresize" : true,
33533 "beforeapply" : true
33536 Roo.util.Observable.call(this);
33539 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33540 onStartProxyDrag : function(x, y){
33541 this.fireEvent("beforeresize", this);
33543 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33545 o.enableDisplayMode("block");
33546 // all splitbars share the same overlay
33547 Roo.bootstrap.SplitBar.prototype.overlay = o;
33549 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33550 this.overlay.show();
33551 Roo.get(this.proxy).setDisplayed("block");
33552 var size = this.adapter.getElementSize(this);
33553 this.activeMinSize = this.getMinimumSize();;
33554 this.activeMaxSize = this.getMaximumSize();;
33555 var c1 = size - this.activeMinSize;
33556 var c2 = Math.max(this.activeMaxSize - size, 0);
33557 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33558 this.dd.resetConstraints();
33559 this.dd.setXConstraint(
33560 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33561 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33563 this.dd.setYConstraint(0, 0);
33565 this.dd.resetConstraints();
33566 this.dd.setXConstraint(0, 0);
33567 this.dd.setYConstraint(
33568 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33569 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33572 this.dragSpecs.startSize = size;
33573 this.dragSpecs.startPoint = [x, y];
33574 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33578 * @private Called after the drag operation by the DDProxy
33580 onEndProxyDrag : function(e){
33581 Roo.get(this.proxy).setDisplayed(false);
33582 var endPoint = Roo.lib.Event.getXY(e);
33584 this.overlay.hide();
33587 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33588 newSize = this.dragSpecs.startSize +
33589 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33590 endPoint[0] - this.dragSpecs.startPoint[0] :
33591 this.dragSpecs.startPoint[0] - endPoint[0]
33594 newSize = this.dragSpecs.startSize +
33595 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33596 endPoint[1] - this.dragSpecs.startPoint[1] :
33597 this.dragSpecs.startPoint[1] - endPoint[1]
33600 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33601 if(newSize != this.dragSpecs.startSize){
33602 if(this.fireEvent('beforeapply', this, newSize) !== false){
33603 this.adapter.setElementSize(this, newSize);
33604 this.fireEvent("moved", this, newSize);
33605 this.fireEvent("resize", this, newSize);
33611 * Get the adapter this SplitBar uses
33612 * @return The adapter object
33614 getAdapter : function(){
33615 return this.adapter;
33619 * Set the adapter this SplitBar uses
33620 * @param {Object} adapter A SplitBar adapter object
33622 setAdapter : function(adapter){
33623 this.adapter = adapter;
33624 this.adapter.init(this);
33628 * Gets the minimum size for the resizing element
33629 * @return {Number} The minimum size
33631 getMinimumSize : function(){
33632 return this.minSize;
33636 * Sets the minimum size for the resizing element
33637 * @param {Number} minSize The minimum size
33639 setMinimumSize : function(minSize){
33640 this.minSize = minSize;
33644 * Gets the maximum size for the resizing element
33645 * @return {Number} The maximum size
33647 getMaximumSize : function(){
33648 return this.maxSize;
33652 * Sets the maximum size for the resizing element
33653 * @param {Number} maxSize The maximum size
33655 setMaximumSize : function(maxSize){
33656 this.maxSize = maxSize;
33660 * Sets the initialize size for the resizing element
33661 * @param {Number} size The initial size
33663 setCurrentSize : function(size){
33664 var oldAnimate = this.animate;
33665 this.animate = false;
33666 this.adapter.setElementSize(this, size);
33667 this.animate = oldAnimate;
33671 * Destroy this splitbar.
33672 * @param {Boolean} removeEl True to remove the element
33674 destroy : function(removeEl){
33676 this.shim.remove();
33679 this.proxy.parentNode.removeChild(this.proxy);
33687 * @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.
33689 Roo.bootstrap.SplitBar.createProxy = function(dir){
33690 var proxy = new Roo.Element(document.createElement("div"));
33691 proxy.unselectable();
33692 var cls = 'roo-splitbar-proxy';
33693 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33694 document.body.appendChild(proxy.dom);
33699 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33700 * Default Adapter. It assumes the splitter and resizing element are not positioned
33701 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33703 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33706 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33707 // do nothing for now
33708 init : function(s){
33712 * Called before drag operations to get the current size of the resizing element.
33713 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33715 getElementSize : function(s){
33716 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33717 return s.resizingEl.getWidth();
33719 return s.resizingEl.getHeight();
33724 * Called after drag operations to set the size of the resizing element.
33725 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33726 * @param {Number} newSize The new size to set
33727 * @param {Function} onComplete A function to be invoked when resizing is complete
33729 setElementSize : function(s, newSize, onComplete){
33730 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33732 s.resizingEl.setWidth(newSize);
33734 onComplete(s, newSize);
33737 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33742 s.resizingEl.setHeight(newSize);
33744 onComplete(s, newSize);
33747 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33754 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33755 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33756 * Adapter that moves the splitter element to align with the resized sizing element.
33757 * Used with an absolute positioned SplitBar.
33758 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33759 * document.body, make sure you assign an id to the body element.
33761 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33762 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33763 this.container = Roo.get(container);
33766 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33767 init : function(s){
33768 this.basic.init(s);
33771 getElementSize : function(s){
33772 return this.basic.getElementSize(s);
33775 setElementSize : function(s, newSize, onComplete){
33776 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33779 moveSplitter : function(s){
33780 var yes = Roo.bootstrap.SplitBar;
33781 switch(s.placement){
33783 s.el.setX(s.resizingEl.getRight());
33786 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33789 s.el.setY(s.resizingEl.getBottom());
33792 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33799 * Orientation constant - Create a vertical SplitBar
33803 Roo.bootstrap.SplitBar.VERTICAL = 1;
33806 * Orientation constant - Create a horizontal SplitBar
33810 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33813 * Placement constant - The resizing element is to the left of the splitter element
33817 Roo.bootstrap.SplitBar.LEFT = 1;
33820 * Placement constant - The resizing element is to the right of the splitter element
33824 Roo.bootstrap.SplitBar.RIGHT = 2;
33827 * Placement constant - The resizing element is positioned above the splitter element
33831 Roo.bootstrap.SplitBar.TOP = 3;
33834 * Placement constant - The resizing element is positioned under splitter element
33838 Roo.bootstrap.SplitBar.BOTTOM = 4;
33839 Roo.namespace("Roo.bootstrap.layout");/*
33841 * Ext JS Library 1.1.1
33842 * Copyright(c) 2006-2007, Ext JS, LLC.
33844 * Originally Released Under LGPL - original licence link has changed is not relivant.
33847 * <script type="text/javascript">
33851 * @class Roo.bootstrap.layout.Manager
33852 * @extends Roo.bootstrap.Component
33853 * Base class for layout managers.
33855 Roo.bootstrap.layout.Manager = function(config)
33857 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33863 /** false to disable window resize monitoring @type Boolean */
33864 this.monitorWindowResize = true;
33869 * Fires when a layout is performed.
33870 * @param {Roo.LayoutManager} this
33874 * @event regionresized
33875 * Fires when the user resizes a region.
33876 * @param {Roo.LayoutRegion} region The resized region
33877 * @param {Number} newSize The new size (width for east/west, height for north/south)
33879 "regionresized" : true,
33881 * @event regioncollapsed
33882 * Fires when a region is collapsed.
33883 * @param {Roo.LayoutRegion} region The collapsed region
33885 "regioncollapsed" : true,
33887 * @event regionexpanded
33888 * Fires when a region is expanded.
33889 * @param {Roo.LayoutRegion} region The expanded region
33891 "regionexpanded" : true
33893 this.updating = false;
33896 this.el = Roo.get(config.el);
33902 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33907 monitorWindowResize : true,
33913 onRender : function(ct, position)
33916 this.el = Roo.get(ct);
33919 //this.fireEvent('render',this);
33923 initEvents: function()
33927 // ie scrollbar fix
33928 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33929 document.body.scroll = "no";
33930 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33931 this.el.position('relative');
33933 this.id = this.el.id;
33934 this.el.addClass("roo-layout-container");
33935 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33936 if(this.el.dom != document.body ) {
33937 this.el.on('resize', this.layout,this);
33938 this.el.on('show', this.layout,this);
33944 * Returns true if this layout is currently being updated
33945 * @return {Boolean}
33947 isUpdating : function(){
33948 return this.updating;
33952 * Suspend the LayoutManager from doing auto-layouts while
33953 * making multiple add or remove calls
33955 beginUpdate : function(){
33956 this.updating = true;
33960 * Restore auto-layouts and optionally disable the manager from performing a layout
33961 * @param {Boolean} noLayout true to disable a layout update
33963 endUpdate : function(noLayout){
33964 this.updating = false;
33970 layout: function(){
33974 onRegionResized : function(region, newSize){
33975 this.fireEvent("regionresized", region, newSize);
33979 onRegionCollapsed : function(region){
33980 this.fireEvent("regioncollapsed", region);
33983 onRegionExpanded : function(region){
33984 this.fireEvent("regionexpanded", region);
33988 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33989 * performs box-model adjustments.
33990 * @return {Object} The size as an object {width: (the width), height: (the height)}
33992 getViewSize : function()
33995 if(this.el.dom != document.body){
33996 size = this.el.getSize();
33998 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34000 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34001 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34006 * Returns the Element this layout is bound to.
34007 * @return {Roo.Element}
34009 getEl : function(){
34014 * Returns the specified region.
34015 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34016 * @return {Roo.LayoutRegion}
34018 getRegion : function(target){
34019 return this.regions[target.toLowerCase()];
34022 onWindowResize : function(){
34023 if(this.monitorWindowResize){
34030 * Ext JS Library 1.1.1
34031 * Copyright(c) 2006-2007, Ext JS, LLC.
34033 * Originally Released Under LGPL - original licence link has changed is not relivant.
34036 * <script type="text/javascript">
34039 * @class Roo.bootstrap.layout.Border
34040 * @extends Roo.bootstrap.layout.Manager
34041 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34042 * please see: examples/bootstrap/nested.html<br><br>
34044 <b>The container the layout is rendered into can be either the body element or any other element.
34045 If it is not the body element, the container needs to either be an absolute positioned element,
34046 or you will need to add "position:relative" to the css of the container. You will also need to specify
34047 the container size if it is not the body element.</b>
34050 * Create a new Border
34051 * @param {Object} config Configuration options
34053 Roo.bootstrap.layout.Border = function(config){
34054 config = config || {};
34055 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34059 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34060 if(config[region]){
34061 config[region].region = region;
34062 this.addRegion(config[region]);
34068 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34070 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34072 * Creates and adds a new region if it doesn't already exist.
34073 * @param {String} target The target region key (north, south, east, west or center).
34074 * @param {Object} config The regions config object
34075 * @return {BorderLayoutRegion} The new region
34077 addRegion : function(config)
34079 if(!this.regions[config.region]){
34080 var r = this.factory(config);
34081 this.bindRegion(r);
34083 return this.regions[config.region];
34087 bindRegion : function(r){
34088 this.regions[r.config.region] = r;
34090 r.on("visibilitychange", this.layout, this);
34091 r.on("paneladded", this.layout, this);
34092 r.on("panelremoved", this.layout, this);
34093 r.on("invalidated", this.layout, this);
34094 r.on("resized", this.onRegionResized, this);
34095 r.on("collapsed", this.onRegionCollapsed, this);
34096 r.on("expanded", this.onRegionExpanded, this);
34100 * Performs a layout update.
34102 layout : function()
34104 if(this.updating) {
34108 // render all the rebions if they have not been done alreayd?
34109 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34110 if(this.regions[region] && !this.regions[region].bodyEl){
34111 this.regions[region].onRender(this.el)
34115 var size = this.getViewSize();
34116 var w = size.width;
34117 var h = size.height;
34122 //var x = 0, y = 0;
34124 var rs = this.regions;
34125 var north = rs["north"];
34126 var south = rs["south"];
34127 var west = rs["west"];
34128 var east = rs["east"];
34129 var center = rs["center"];
34130 //if(this.hideOnLayout){ // not supported anymore
34131 //c.el.setStyle("display", "none");
34133 if(north && north.isVisible()){
34134 var b = north.getBox();
34135 var m = north.getMargins();
34136 b.width = w - (m.left+m.right);
34139 centerY = b.height + b.y + m.bottom;
34140 centerH -= centerY;
34141 north.updateBox(this.safeBox(b));
34143 if(south && south.isVisible()){
34144 var b = south.getBox();
34145 var m = south.getMargins();
34146 b.width = w - (m.left+m.right);
34148 var totalHeight = (b.height + m.top + m.bottom);
34149 b.y = h - totalHeight + m.top;
34150 centerH -= totalHeight;
34151 south.updateBox(this.safeBox(b));
34153 if(west && west.isVisible()){
34154 var b = west.getBox();
34155 var m = west.getMargins();
34156 b.height = centerH - (m.top+m.bottom);
34158 b.y = centerY + m.top;
34159 var totalWidth = (b.width + m.left + m.right);
34160 centerX += totalWidth;
34161 centerW -= totalWidth;
34162 west.updateBox(this.safeBox(b));
34164 if(east && east.isVisible()){
34165 var b = east.getBox();
34166 var m = east.getMargins();
34167 b.height = centerH - (m.top+m.bottom);
34168 var totalWidth = (b.width + m.left + m.right);
34169 b.x = w - totalWidth + m.left;
34170 b.y = centerY + m.top;
34171 centerW -= totalWidth;
34172 east.updateBox(this.safeBox(b));
34175 var m = center.getMargins();
34177 x: centerX + m.left,
34178 y: centerY + m.top,
34179 width: centerW - (m.left+m.right),
34180 height: centerH - (m.top+m.bottom)
34182 //if(this.hideOnLayout){
34183 //center.el.setStyle("display", "block");
34185 center.updateBox(this.safeBox(centerBox));
34188 this.fireEvent("layout", this);
34192 safeBox : function(box){
34193 box.width = Math.max(0, box.width);
34194 box.height = Math.max(0, box.height);
34199 * Adds a ContentPanel (or subclass) to this layout.
34200 * @param {String} target The target region key (north, south, east, west or center).
34201 * @param {Roo.ContentPanel} panel The panel to add
34202 * @return {Roo.ContentPanel} The added panel
34204 add : function(target, panel){
34206 target = target.toLowerCase();
34207 return this.regions[target].add(panel);
34211 * Remove a ContentPanel (or subclass) to this layout.
34212 * @param {String} target The target region key (north, south, east, west or center).
34213 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34214 * @return {Roo.ContentPanel} The removed panel
34216 remove : function(target, panel){
34217 target = target.toLowerCase();
34218 return this.regions[target].remove(panel);
34222 * Searches all regions for a panel with the specified id
34223 * @param {String} panelId
34224 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34226 findPanel : function(panelId){
34227 var rs = this.regions;
34228 for(var target in rs){
34229 if(typeof rs[target] != "function"){
34230 var p = rs[target].getPanel(panelId);
34240 * Searches all regions for a panel with the specified id and activates (shows) it.
34241 * @param {String/ContentPanel} panelId The panels id or the panel itself
34242 * @return {Roo.ContentPanel} The shown panel or null
34244 showPanel : function(panelId) {
34245 var rs = this.regions;
34246 for(var target in rs){
34247 var r = rs[target];
34248 if(typeof r != "function"){
34249 if(r.hasPanel(panelId)){
34250 return r.showPanel(panelId);
34258 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34259 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34262 restoreState : function(provider){
34264 provider = Roo.state.Manager;
34266 var sm = new Roo.LayoutStateManager();
34267 sm.init(this, provider);
34273 * Adds a xtype elements to the layout.
34277 xtype : 'ContentPanel',
34284 xtype : 'NestedLayoutPanel',
34290 items : [ ... list of content panels or nested layout panels.. ]
34294 * @param {Object} cfg Xtype definition of item to add.
34296 addxtype : function(cfg)
34298 // basically accepts a pannel...
34299 // can accept a layout region..!?!?
34300 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34303 // theory? children can only be panels??
34305 //if (!cfg.xtype.match(/Panel$/)) {
34310 if (typeof(cfg.region) == 'undefined') {
34311 Roo.log("Failed to add Panel, region was not set");
34315 var region = cfg.region;
34321 xitems = cfg.items;
34328 case 'Content': // ContentPanel (el, cfg)
34329 case 'Scroll': // ContentPanel (el, cfg)
34331 cfg.autoCreate = true;
34332 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34334 // var el = this.el.createChild();
34335 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34338 this.add(region, ret);
34342 case 'TreePanel': // our new panel!
34343 cfg.el = this.el.createChild();
34344 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34345 this.add(region, ret);
34350 // create a new Layout (which is a Border Layout...
34352 var clayout = cfg.layout;
34353 clayout.el = this.el.createChild();
34354 clayout.items = clayout.items || [];
34358 // replace this exitems with the clayout ones..
34359 xitems = clayout.items;
34361 // force background off if it's in center...
34362 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34363 cfg.background = false;
34365 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34368 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34369 //console.log('adding nested layout panel ' + cfg.toSource());
34370 this.add(region, ret);
34371 nb = {}; /// find first...
34376 // needs grid and region
34378 //var el = this.getRegion(region).el.createChild();
34380 *var el = this.el.createChild();
34381 // create the grid first...
34382 cfg.grid.container = el;
34383 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34386 if (region == 'center' && this.active ) {
34387 cfg.background = false;
34390 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34392 this.add(region, ret);
34394 if (cfg.background) {
34395 // render grid on panel activation (if panel background)
34396 ret.on('activate', function(gp) {
34397 if (!gp.grid.rendered) {
34398 // gp.grid.render(el);
34402 // cfg.grid.render(el);
34408 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34409 // it was the old xcomponent building that caused this before.
34410 // espeically if border is the top element in the tree.
34420 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34422 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34423 this.add(region, ret);
34427 throw "Can not add '" + cfg.xtype + "' to Border";
34433 this.beginUpdate();
34437 Roo.each(xitems, function(i) {
34438 region = nb && i.region ? i.region : false;
34440 var add = ret.addxtype(i);
34443 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34444 if (!i.background) {
34445 abn[region] = nb[region] ;
34452 // make the last non-background panel active..
34453 //if (nb) { Roo.log(abn); }
34456 for(var r in abn) {
34457 region = this.getRegion(r);
34459 // tried using nb[r], but it does not work..
34461 region.showPanel(abn[r]);
34472 factory : function(cfg)
34475 var validRegions = Roo.bootstrap.layout.Border.regions;
34477 var target = cfg.region;
34480 var r = Roo.bootstrap.layout;
34484 return new r.North(cfg);
34486 return new r.South(cfg);
34488 return new r.East(cfg);
34490 return new r.West(cfg);
34492 return new r.Center(cfg);
34494 throw 'Layout region "'+target+'" not supported.';
34501 * Ext JS Library 1.1.1
34502 * Copyright(c) 2006-2007, Ext JS, LLC.
34504 * Originally Released Under LGPL - original licence link has changed is not relivant.
34507 * <script type="text/javascript">
34511 * @class Roo.bootstrap.layout.Basic
34512 * @extends Roo.util.Observable
34513 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34514 * and does not have a titlebar, tabs or any other features. All it does is size and position
34515 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34516 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34517 * @cfg {string} region the region that it inhabits..
34518 * @cfg {bool} skipConfig skip config?
34522 Roo.bootstrap.layout.Basic = function(config){
34524 this.mgr = config.mgr;
34526 this.position = config.region;
34528 var skipConfig = config.skipConfig;
34532 * @scope Roo.BasicLayoutRegion
34536 * @event beforeremove
34537 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34538 * @param {Roo.LayoutRegion} this
34539 * @param {Roo.ContentPanel} panel The panel
34540 * @param {Object} e The cancel event object
34542 "beforeremove" : true,
34544 * @event invalidated
34545 * Fires when the layout for this region is changed.
34546 * @param {Roo.LayoutRegion} this
34548 "invalidated" : true,
34550 * @event visibilitychange
34551 * Fires when this region is shown or hidden
34552 * @param {Roo.LayoutRegion} this
34553 * @param {Boolean} visibility true or false
34555 "visibilitychange" : true,
34557 * @event paneladded
34558 * Fires when a panel is added.
34559 * @param {Roo.LayoutRegion} this
34560 * @param {Roo.ContentPanel} panel The panel
34562 "paneladded" : true,
34564 * @event panelremoved
34565 * Fires when a panel is removed.
34566 * @param {Roo.LayoutRegion} this
34567 * @param {Roo.ContentPanel} panel The panel
34569 "panelremoved" : true,
34571 * @event beforecollapse
34572 * Fires when this region before collapse.
34573 * @param {Roo.LayoutRegion} this
34575 "beforecollapse" : true,
34578 * Fires when this region is collapsed.
34579 * @param {Roo.LayoutRegion} this
34581 "collapsed" : true,
34584 * Fires when this region is expanded.
34585 * @param {Roo.LayoutRegion} this
34590 * Fires when this region is slid into view.
34591 * @param {Roo.LayoutRegion} this
34593 "slideshow" : true,
34596 * Fires when this region slides out of view.
34597 * @param {Roo.LayoutRegion} this
34599 "slidehide" : true,
34601 * @event panelactivated
34602 * Fires when a panel is activated.
34603 * @param {Roo.LayoutRegion} this
34604 * @param {Roo.ContentPanel} panel The activated panel
34606 "panelactivated" : true,
34609 * Fires when the user resizes this region.
34610 * @param {Roo.LayoutRegion} this
34611 * @param {Number} newSize The new size (width for east/west, height for north/south)
34615 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34616 this.panels = new Roo.util.MixedCollection();
34617 this.panels.getKey = this.getPanelId.createDelegate(this);
34619 this.activePanel = null;
34620 // ensure listeners are added...
34622 if (config.listeners || config.events) {
34623 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34624 listeners : config.listeners || {},
34625 events : config.events || {}
34629 if(skipConfig !== true){
34630 this.applyConfig(config);
34634 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34636 getPanelId : function(p){
34640 applyConfig : function(config){
34641 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34642 this.config = config;
34647 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34648 * the width, for horizontal (north, south) the height.
34649 * @param {Number} newSize The new width or height
34651 resizeTo : function(newSize){
34652 var el = this.el ? this.el :
34653 (this.activePanel ? this.activePanel.getEl() : null);
34655 switch(this.position){
34658 el.setWidth(newSize);
34659 this.fireEvent("resized", this, newSize);
34663 el.setHeight(newSize);
34664 this.fireEvent("resized", this, newSize);
34670 getBox : function(){
34671 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34674 getMargins : function(){
34675 return this.margins;
34678 updateBox : function(box){
34680 var el = this.activePanel.getEl();
34681 el.dom.style.left = box.x + "px";
34682 el.dom.style.top = box.y + "px";
34683 this.activePanel.setSize(box.width, box.height);
34687 * Returns the container element for this region.
34688 * @return {Roo.Element}
34690 getEl : function(){
34691 return this.activePanel;
34695 * Returns true if this region is currently visible.
34696 * @return {Boolean}
34698 isVisible : function(){
34699 return this.activePanel ? true : false;
34702 setActivePanel : function(panel){
34703 panel = this.getPanel(panel);
34704 if(this.activePanel && this.activePanel != panel){
34705 this.activePanel.setActiveState(false);
34706 this.activePanel.getEl().setLeftTop(-10000,-10000);
34708 this.activePanel = panel;
34709 panel.setActiveState(true);
34711 panel.setSize(this.box.width, this.box.height);
34713 this.fireEvent("panelactivated", this, panel);
34714 this.fireEvent("invalidated");
34718 * Show the specified panel.
34719 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34720 * @return {Roo.ContentPanel} The shown panel or null
34722 showPanel : function(panel){
34723 panel = this.getPanel(panel);
34725 this.setActivePanel(panel);
34731 * Get the active panel for this region.
34732 * @return {Roo.ContentPanel} The active panel or null
34734 getActivePanel : function(){
34735 return this.activePanel;
34739 * Add the passed ContentPanel(s)
34740 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34741 * @return {Roo.ContentPanel} The panel added (if only one was added)
34743 add : function(panel){
34744 if(arguments.length > 1){
34745 for(var i = 0, len = arguments.length; i < len; i++) {
34746 this.add(arguments[i]);
34750 if(this.hasPanel(panel)){
34751 this.showPanel(panel);
34754 var el = panel.getEl();
34755 if(el.dom.parentNode != this.mgr.el.dom){
34756 this.mgr.el.dom.appendChild(el.dom);
34758 if(panel.setRegion){
34759 panel.setRegion(this);
34761 this.panels.add(panel);
34762 el.setStyle("position", "absolute");
34763 if(!panel.background){
34764 this.setActivePanel(panel);
34765 if(this.config.initialSize && this.panels.getCount()==1){
34766 this.resizeTo(this.config.initialSize);
34769 this.fireEvent("paneladded", this, panel);
34774 * Returns true if the panel is in this region.
34775 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34776 * @return {Boolean}
34778 hasPanel : function(panel){
34779 if(typeof panel == "object"){ // must be panel obj
34780 panel = panel.getId();
34782 return this.getPanel(panel) ? true : false;
34786 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34787 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34788 * @param {Boolean} preservePanel Overrides the config preservePanel option
34789 * @return {Roo.ContentPanel} The panel that was removed
34791 remove : function(panel, preservePanel){
34792 panel = this.getPanel(panel);
34797 this.fireEvent("beforeremove", this, panel, e);
34798 if(e.cancel === true){
34801 var panelId = panel.getId();
34802 this.panels.removeKey(panelId);
34807 * Returns the panel specified or null if it's not in this region.
34808 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34809 * @return {Roo.ContentPanel}
34811 getPanel : function(id){
34812 if(typeof id == "object"){ // must be panel obj
34815 return this.panels.get(id);
34819 * Returns this regions position (north/south/east/west/center).
34822 getPosition: function(){
34823 return this.position;
34827 * Ext JS Library 1.1.1
34828 * Copyright(c) 2006-2007, Ext JS, LLC.
34830 * Originally Released Under LGPL - original licence link has changed is not relivant.
34833 * <script type="text/javascript">
34837 * @class Roo.bootstrap.layout.Region
34838 * @extends Roo.bootstrap.layout.Basic
34839 * This class represents a region in a layout manager.
34841 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34842 * @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})
34843 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34844 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34845 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34846 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34847 * @cfg {String} title The title for the region (overrides panel titles)
34848 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34849 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34850 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34851 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34852 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34853 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34854 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34855 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34856 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34857 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34859 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34860 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34861 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34862 * @cfg {Number} width For East/West panels
34863 * @cfg {Number} height For North/South panels
34864 * @cfg {Boolean} split To show the splitter
34865 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34867 * @cfg {string} cls Extra CSS classes to add to region
34869 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34870 * @cfg {string} region the region that it inhabits..
34873 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34874 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34876 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34877 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34878 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34880 Roo.bootstrap.layout.Region = function(config)
34882 this.applyConfig(config);
34884 var mgr = config.mgr;
34885 var pos = config.region;
34886 config.skipConfig = true;
34887 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34890 this.onRender(mgr.el);
34893 this.visible = true;
34894 this.collapsed = false;
34895 this.unrendered_panels = [];
34898 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34900 position: '', // set by wrapper (eg. north/south etc..)
34901 unrendered_panels : null, // unrendered panels.
34902 createBody : function(){
34903 /** This region's body element
34904 * @type Roo.Element */
34905 this.bodyEl = this.el.createChild({
34907 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34911 onRender: function(ctr, pos)
34913 var dh = Roo.DomHelper;
34914 /** This region's container element
34915 * @type Roo.Element */
34916 this.el = dh.append(ctr.dom, {
34918 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34920 /** This region's title element
34921 * @type Roo.Element */
34923 this.titleEl = dh.append(this.el.dom,
34926 unselectable: "on",
34927 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34929 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34930 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34933 this.titleEl.enableDisplayMode();
34934 /** This region's title text element
34935 * @type HTMLElement */
34936 this.titleTextEl = this.titleEl.dom.firstChild;
34937 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34939 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34940 this.closeBtn.enableDisplayMode();
34941 this.closeBtn.on("click", this.closeClicked, this);
34942 this.closeBtn.hide();
34944 this.createBody(this.config);
34945 if(this.config.hideWhenEmpty){
34947 this.on("paneladded", this.validateVisibility, this);
34948 this.on("panelremoved", this.validateVisibility, this);
34950 if(this.autoScroll){
34951 this.bodyEl.setStyle("overflow", "auto");
34953 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34955 //if(c.titlebar !== false){
34956 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34957 this.titleEl.hide();
34959 this.titleEl.show();
34960 if(this.config.title){
34961 this.titleTextEl.innerHTML = this.config.title;
34965 if(this.config.collapsed){
34966 this.collapse(true);
34968 if(this.config.hidden){
34972 if (this.unrendered_panels && this.unrendered_panels.length) {
34973 for (var i =0;i< this.unrendered_panels.length; i++) {
34974 this.add(this.unrendered_panels[i]);
34976 this.unrendered_panels = null;
34982 applyConfig : function(c)
34985 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34986 var dh = Roo.DomHelper;
34987 if(c.titlebar !== false){
34988 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34989 this.collapseBtn.on("click", this.collapse, this);
34990 this.collapseBtn.enableDisplayMode();
34992 if(c.showPin === true || this.showPin){
34993 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34994 this.stickBtn.enableDisplayMode();
34995 this.stickBtn.on("click", this.expand, this);
34996 this.stickBtn.hide();
35001 /** This region's collapsed element
35002 * @type Roo.Element */
35005 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35006 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35009 if(c.floatable !== false){
35010 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35011 this.collapsedEl.on("click", this.collapseClick, this);
35014 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35015 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35016 id: "message", unselectable: "on", style:{"float":"left"}});
35017 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35019 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35020 this.expandBtn.on("click", this.expand, this);
35024 if(this.collapseBtn){
35025 this.collapseBtn.setVisible(c.collapsible == true);
35028 this.cmargins = c.cmargins || this.cmargins ||
35029 (this.position == "west" || this.position == "east" ?
35030 {top: 0, left: 2, right:2, bottom: 0} :
35031 {top: 2, left: 0, right:0, bottom: 2});
35033 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35036 this.bottomTabs = c.tabPosition != "top";
35038 this.autoScroll = c.autoScroll || false;
35043 this.duration = c.duration || .30;
35044 this.slideDuration = c.slideDuration || .45;
35049 * Returns true if this region is currently visible.
35050 * @return {Boolean}
35052 isVisible : function(){
35053 return this.visible;
35057 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35058 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35060 //setCollapsedTitle : function(title){
35061 // title = title || " ";
35062 // if(this.collapsedTitleTextEl){
35063 // this.collapsedTitleTextEl.innerHTML = title;
35067 getBox : function(){
35069 // if(!this.collapsed){
35070 b = this.el.getBox(false, true);
35072 // b = this.collapsedEl.getBox(false, true);
35077 getMargins : function(){
35078 return this.margins;
35079 //return this.collapsed ? this.cmargins : this.margins;
35082 highlight : function(){
35083 this.el.addClass("x-layout-panel-dragover");
35086 unhighlight : function(){
35087 this.el.removeClass("x-layout-panel-dragover");
35090 updateBox : function(box)
35092 if (!this.bodyEl) {
35093 return; // not rendered yet..
35097 if(!this.collapsed){
35098 this.el.dom.style.left = box.x + "px";
35099 this.el.dom.style.top = box.y + "px";
35100 this.updateBody(box.width, box.height);
35102 this.collapsedEl.dom.style.left = box.x + "px";
35103 this.collapsedEl.dom.style.top = box.y + "px";
35104 this.collapsedEl.setSize(box.width, box.height);
35107 this.tabs.autoSizeTabs();
35111 updateBody : function(w, h)
35114 this.el.setWidth(w);
35115 w -= this.el.getBorderWidth("rl");
35116 if(this.config.adjustments){
35117 w += this.config.adjustments[0];
35120 if(h !== null && h > 0){
35121 this.el.setHeight(h);
35122 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35123 h -= this.el.getBorderWidth("tb");
35124 if(this.config.adjustments){
35125 h += this.config.adjustments[1];
35127 this.bodyEl.setHeight(h);
35129 h = this.tabs.syncHeight(h);
35132 if(this.panelSize){
35133 w = w !== null ? w : this.panelSize.width;
35134 h = h !== null ? h : this.panelSize.height;
35136 if(this.activePanel){
35137 var el = this.activePanel.getEl();
35138 w = w !== null ? w : el.getWidth();
35139 h = h !== null ? h : el.getHeight();
35140 this.panelSize = {width: w, height: h};
35141 this.activePanel.setSize(w, h);
35143 if(Roo.isIE && this.tabs){
35144 this.tabs.el.repaint();
35149 * Returns the container element for this region.
35150 * @return {Roo.Element}
35152 getEl : function(){
35157 * Hides this region.
35160 //if(!this.collapsed){
35161 this.el.dom.style.left = "-2000px";
35164 // this.collapsedEl.dom.style.left = "-2000px";
35165 // this.collapsedEl.hide();
35167 this.visible = false;
35168 this.fireEvent("visibilitychange", this, false);
35172 * Shows this region if it was previously hidden.
35175 //if(!this.collapsed){
35178 // this.collapsedEl.show();
35180 this.visible = true;
35181 this.fireEvent("visibilitychange", this, true);
35184 closeClicked : function(){
35185 if(this.activePanel){
35186 this.remove(this.activePanel);
35190 collapseClick : function(e){
35192 e.stopPropagation();
35195 e.stopPropagation();
35201 * Collapses this region.
35202 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35205 collapse : function(skipAnim, skipCheck = false){
35206 if(this.collapsed) {
35210 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35212 this.collapsed = true;
35214 this.split.el.hide();
35216 if(this.config.animate && skipAnim !== true){
35217 this.fireEvent("invalidated", this);
35218 this.animateCollapse();
35220 this.el.setLocation(-20000,-20000);
35222 this.collapsedEl.show();
35223 this.fireEvent("collapsed", this);
35224 this.fireEvent("invalidated", this);
35230 animateCollapse : function(){
35235 * Expands this region if it was previously collapsed.
35236 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35237 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35240 expand : function(e, skipAnim){
35242 e.stopPropagation();
35244 if(!this.collapsed || this.el.hasActiveFx()) {
35248 this.afterSlideIn();
35251 this.collapsed = false;
35252 if(this.config.animate && skipAnim !== true){
35253 this.animateExpand();
35257 this.split.el.show();
35259 this.collapsedEl.setLocation(-2000,-2000);
35260 this.collapsedEl.hide();
35261 this.fireEvent("invalidated", this);
35262 this.fireEvent("expanded", this);
35266 animateExpand : function(){
35270 initTabs : function()
35272 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35274 var ts = new Roo.bootstrap.panel.Tabs({
35275 el: this.bodyEl.dom,
35276 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35277 disableTooltips: this.config.disableTabTips,
35278 toolbar : this.config.toolbar
35281 if(this.config.hideTabs){
35282 ts.stripWrap.setDisplayed(false);
35285 ts.resizeTabs = this.config.resizeTabs === true;
35286 ts.minTabWidth = this.config.minTabWidth || 40;
35287 ts.maxTabWidth = this.config.maxTabWidth || 250;
35288 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35289 ts.monitorResize = false;
35290 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35291 ts.bodyEl.addClass('roo-layout-tabs-body');
35292 this.panels.each(this.initPanelAsTab, this);
35295 initPanelAsTab : function(panel){
35296 var ti = this.tabs.addTab(
35300 this.config.closeOnTab && panel.isClosable(),
35303 if(panel.tabTip !== undefined){
35304 ti.setTooltip(panel.tabTip);
35306 ti.on("activate", function(){
35307 this.setActivePanel(panel);
35310 if(this.config.closeOnTab){
35311 ti.on("beforeclose", function(t, e){
35313 this.remove(panel);
35317 panel.tabItem = ti;
35322 updatePanelTitle : function(panel, title)
35324 if(this.activePanel == panel){
35325 this.updateTitle(title);
35328 var ti = this.tabs.getTab(panel.getEl().id);
35330 if(panel.tabTip !== undefined){
35331 ti.setTooltip(panel.tabTip);
35336 updateTitle : function(title){
35337 if(this.titleTextEl && !this.config.title){
35338 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35342 setActivePanel : function(panel)
35344 panel = this.getPanel(panel);
35345 if(this.activePanel && this.activePanel != panel){
35346 this.activePanel.setActiveState(false);
35348 this.activePanel = panel;
35349 panel.setActiveState(true);
35350 if(this.panelSize){
35351 panel.setSize(this.panelSize.width, this.panelSize.height);
35354 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35356 this.updateTitle(panel.getTitle());
35358 this.fireEvent("invalidated", this);
35360 this.fireEvent("panelactivated", this, panel);
35364 * Shows the specified panel.
35365 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35366 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35368 showPanel : function(panel)
35370 panel = this.getPanel(panel);
35373 var tab = this.tabs.getTab(panel.getEl().id);
35374 if(tab.isHidden()){
35375 this.tabs.unhideTab(tab.id);
35379 this.setActivePanel(panel);
35386 * Get the active panel for this region.
35387 * @return {Roo.ContentPanel} The active panel or null
35389 getActivePanel : function(){
35390 return this.activePanel;
35393 validateVisibility : function(){
35394 if(this.panels.getCount() < 1){
35395 this.updateTitle(" ");
35396 this.closeBtn.hide();
35399 if(!this.isVisible()){
35406 * Adds the passed ContentPanel(s) to this region.
35407 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35408 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35410 add : function(panel)
35412 if(arguments.length > 1){
35413 for(var i = 0, len = arguments.length; i < len; i++) {
35414 this.add(arguments[i]);
35419 // if we have not been rendered yet, then we can not really do much of this..
35420 if (!this.bodyEl) {
35421 this.unrendered_panels.push(panel);
35428 if(this.hasPanel(panel)){
35429 this.showPanel(panel);
35432 panel.setRegion(this);
35433 this.panels.add(panel);
35434 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35435 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35436 // and hide them... ???
35437 this.bodyEl.dom.appendChild(panel.getEl().dom);
35438 if(panel.background !== true){
35439 this.setActivePanel(panel);
35441 this.fireEvent("paneladded", this, panel);
35448 this.initPanelAsTab(panel);
35452 if(panel.background !== true){
35453 this.tabs.activate(panel.getEl().id);
35455 this.fireEvent("paneladded", this, panel);
35460 * Hides the tab for the specified panel.
35461 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35463 hidePanel : function(panel){
35464 if(this.tabs && (panel = this.getPanel(panel))){
35465 this.tabs.hideTab(panel.getEl().id);
35470 * Unhides the tab for a previously hidden panel.
35471 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35473 unhidePanel : function(panel){
35474 if(this.tabs && (panel = this.getPanel(panel))){
35475 this.tabs.unhideTab(panel.getEl().id);
35479 clearPanels : function(){
35480 while(this.panels.getCount() > 0){
35481 this.remove(this.panels.first());
35486 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35487 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35488 * @param {Boolean} preservePanel Overrides the config preservePanel option
35489 * @return {Roo.ContentPanel} The panel that was removed
35491 remove : function(panel, preservePanel)
35493 panel = this.getPanel(panel);
35498 this.fireEvent("beforeremove", this, panel, e);
35499 if(e.cancel === true){
35502 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35503 var panelId = panel.getId();
35504 this.panels.removeKey(panelId);
35506 document.body.appendChild(panel.getEl().dom);
35509 this.tabs.removeTab(panel.getEl().id);
35510 }else if (!preservePanel){
35511 this.bodyEl.dom.removeChild(panel.getEl().dom);
35513 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35514 var p = this.panels.first();
35515 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35516 tempEl.appendChild(p.getEl().dom);
35517 this.bodyEl.update("");
35518 this.bodyEl.dom.appendChild(p.getEl().dom);
35520 this.updateTitle(p.getTitle());
35522 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35523 this.setActivePanel(p);
35525 panel.setRegion(null);
35526 if(this.activePanel == panel){
35527 this.activePanel = null;
35529 if(this.config.autoDestroy !== false && preservePanel !== true){
35530 try{panel.destroy();}catch(e){}
35532 this.fireEvent("panelremoved", this, panel);
35537 * Returns the TabPanel component used by this region
35538 * @return {Roo.TabPanel}
35540 getTabs : function(){
35544 createTool : function(parentEl, className){
35545 var btn = Roo.DomHelper.append(parentEl, {
35547 cls: "x-layout-tools-button",
35550 cls: "roo-layout-tools-button-inner " + className,
35554 btn.addClassOnOver("roo-layout-tools-button-over");
35559 * Ext JS Library 1.1.1
35560 * Copyright(c) 2006-2007, Ext JS, LLC.
35562 * Originally Released Under LGPL - original licence link has changed is not relivant.
35565 * <script type="text/javascript">
35571 * @class Roo.SplitLayoutRegion
35572 * @extends Roo.LayoutRegion
35573 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35575 Roo.bootstrap.layout.Split = function(config){
35576 this.cursor = config.cursor;
35577 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35580 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35582 splitTip : "Drag to resize.",
35583 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35584 useSplitTips : false,
35586 applyConfig : function(config){
35587 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35590 onRender : function(ctr,pos) {
35592 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35593 if(!this.config.split){
35598 var splitEl = Roo.DomHelper.append(ctr.dom, {
35600 id: this.el.id + "-split",
35601 cls: "roo-layout-split roo-layout-split-"+this.position,
35604 /** The SplitBar for this region
35605 * @type Roo.SplitBar */
35606 // does not exist yet...
35607 Roo.log([this.position, this.orientation]);
35609 this.split = new Roo.bootstrap.SplitBar({
35610 dragElement : splitEl,
35611 resizingElement: this.el,
35612 orientation : this.orientation
35615 this.split.on("moved", this.onSplitMove, this);
35616 this.split.useShim = this.config.useShim === true;
35617 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35618 if(this.useSplitTips){
35619 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35621 //if(config.collapsible){
35622 // this.split.el.on("dblclick", this.collapse, this);
35625 if(typeof this.config.minSize != "undefined"){
35626 this.split.minSize = this.config.minSize;
35628 if(typeof this.config.maxSize != "undefined"){
35629 this.split.maxSize = this.config.maxSize;
35631 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35632 this.hideSplitter();
35637 getHMaxSize : function(){
35638 var cmax = this.config.maxSize || 10000;
35639 var center = this.mgr.getRegion("center");
35640 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35643 getVMaxSize : function(){
35644 var cmax = this.config.maxSize || 10000;
35645 var center = this.mgr.getRegion("center");
35646 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35649 onSplitMove : function(split, newSize){
35650 this.fireEvent("resized", this, newSize);
35654 * Returns the {@link Roo.SplitBar} for this region.
35655 * @return {Roo.SplitBar}
35657 getSplitBar : function(){
35662 this.hideSplitter();
35663 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35666 hideSplitter : function(){
35668 this.split.el.setLocation(-2000,-2000);
35669 this.split.el.hide();
35675 this.split.el.show();
35677 Roo.bootstrap.layout.Split.superclass.show.call(this);
35680 beforeSlide: function(){
35681 if(Roo.isGecko){// firefox overflow auto bug workaround
35682 this.bodyEl.clip();
35684 this.tabs.bodyEl.clip();
35686 if(this.activePanel){
35687 this.activePanel.getEl().clip();
35689 if(this.activePanel.beforeSlide){
35690 this.activePanel.beforeSlide();
35696 afterSlide : function(){
35697 if(Roo.isGecko){// firefox overflow auto bug workaround
35698 this.bodyEl.unclip();
35700 this.tabs.bodyEl.unclip();
35702 if(this.activePanel){
35703 this.activePanel.getEl().unclip();
35704 if(this.activePanel.afterSlide){
35705 this.activePanel.afterSlide();
35711 initAutoHide : function(){
35712 if(this.autoHide !== false){
35713 if(!this.autoHideHd){
35714 var st = new Roo.util.DelayedTask(this.slideIn, this);
35715 this.autoHideHd = {
35716 "mouseout": function(e){
35717 if(!e.within(this.el, true)){
35721 "mouseover" : function(e){
35727 this.el.on(this.autoHideHd);
35731 clearAutoHide : function(){
35732 if(this.autoHide !== false){
35733 this.el.un("mouseout", this.autoHideHd.mouseout);
35734 this.el.un("mouseover", this.autoHideHd.mouseover);
35738 clearMonitor : function(){
35739 Roo.get(document).un("click", this.slideInIf, this);
35742 // these names are backwards but not changed for compat
35743 slideOut : function(){
35744 if(this.isSlid || this.el.hasActiveFx()){
35747 this.isSlid = true;
35748 if(this.collapseBtn){
35749 this.collapseBtn.hide();
35751 this.closeBtnState = this.closeBtn.getStyle('display');
35752 this.closeBtn.hide();
35754 this.stickBtn.show();
35757 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35758 this.beforeSlide();
35759 this.el.setStyle("z-index", 10001);
35760 this.el.slideIn(this.getSlideAnchor(), {
35761 callback: function(){
35763 this.initAutoHide();
35764 Roo.get(document).on("click", this.slideInIf, this);
35765 this.fireEvent("slideshow", this);
35772 afterSlideIn : function(){
35773 this.clearAutoHide();
35774 this.isSlid = false;
35775 this.clearMonitor();
35776 this.el.setStyle("z-index", "");
35777 if(this.collapseBtn){
35778 this.collapseBtn.show();
35780 this.closeBtn.setStyle('display', this.closeBtnState);
35782 this.stickBtn.hide();
35784 this.fireEvent("slidehide", this);
35787 slideIn : function(cb){
35788 if(!this.isSlid || this.el.hasActiveFx()){
35792 this.isSlid = false;
35793 this.beforeSlide();
35794 this.el.slideOut(this.getSlideAnchor(), {
35795 callback: function(){
35796 this.el.setLeftTop(-10000, -10000);
35798 this.afterSlideIn();
35806 slideInIf : function(e){
35807 if(!e.within(this.el)){
35812 animateCollapse : function(){
35813 this.beforeSlide();
35814 this.el.setStyle("z-index", 20000);
35815 var anchor = this.getSlideAnchor();
35816 this.el.slideOut(anchor, {
35817 callback : function(){
35818 this.el.setStyle("z-index", "");
35819 this.collapsedEl.slideIn(anchor, {duration:.3});
35821 this.el.setLocation(-10000,-10000);
35823 this.fireEvent("collapsed", this);
35830 animateExpand : function(){
35831 this.beforeSlide();
35832 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35833 this.el.setStyle("z-index", 20000);
35834 this.collapsedEl.hide({
35837 this.el.slideIn(this.getSlideAnchor(), {
35838 callback : function(){
35839 this.el.setStyle("z-index", "");
35842 this.split.el.show();
35844 this.fireEvent("invalidated", this);
35845 this.fireEvent("expanded", this);
35873 getAnchor : function(){
35874 return this.anchors[this.position];
35877 getCollapseAnchor : function(){
35878 return this.canchors[this.position];
35881 getSlideAnchor : function(){
35882 return this.sanchors[this.position];
35885 getAlignAdj : function(){
35886 var cm = this.cmargins;
35887 switch(this.position){
35903 getExpandAdj : function(){
35904 var c = this.collapsedEl, cm = this.cmargins;
35905 switch(this.position){
35907 return [-(cm.right+c.getWidth()+cm.left), 0];
35910 return [cm.right+c.getWidth()+cm.left, 0];
35913 return [0, -(cm.top+cm.bottom+c.getHeight())];
35916 return [0, cm.top+cm.bottom+c.getHeight()];
35922 * Ext JS Library 1.1.1
35923 * Copyright(c) 2006-2007, Ext JS, LLC.
35925 * Originally Released Under LGPL - original licence link has changed is not relivant.
35928 * <script type="text/javascript">
35931 * These classes are private internal classes
35933 Roo.bootstrap.layout.Center = function(config){
35934 config.region = "center";
35935 Roo.bootstrap.layout.Region.call(this, config);
35936 this.visible = true;
35937 this.minWidth = config.minWidth || 20;
35938 this.minHeight = config.minHeight || 20;
35941 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35943 // center panel can't be hidden
35947 // center panel can't be hidden
35950 getMinWidth: function(){
35951 return this.minWidth;
35954 getMinHeight: function(){
35955 return this.minHeight;
35968 Roo.bootstrap.layout.North = function(config)
35970 config.region = 'north';
35971 config.cursor = 'n-resize';
35973 Roo.bootstrap.layout.Split.call(this, config);
35977 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35978 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35979 this.split.el.addClass("roo-layout-split-v");
35981 var size = config.initialSize || config.height;
35982 if(typeof size != "undefined"){
35983 this.el.setHeight(size);
35986 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35988 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35992 getBox : function(){
35993 if(this.collapsed){
35994 return this.collapsedEl.getBox();
35996 var box = this.el.getBox();
35998 box.height += this.split.el.getHeight();
36003 updateBox : function(box){
36004 if(this.split && !this.collapsed){
36005 box.height -= this.split.el.getHeight();
36006 this.split.el.setLeft(box.x);
36007 this.split.el.setTop(box.y+box.height);
36008 this.split.el.setWidth(box.width);
36010 if(this.collapsed){
36011 this.updateBody(box.width, null);
36013 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36021 Roo.bootstrap.layout.South = function(config){
36022 config.region = 'south';
36023 config.cursor = 's-resize';
36024 Roo.bootstrap.layout.Split.call(this, config);
36026 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36027 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36028 this.split.el.addClass("roo-layout-split-v");
36030 var size = config.initialSize || config.height;
36031 if(typeof size != "undefined"){
36032 this.el.setHeight(size);
36036 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36037 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36038 getBox : function(){
36039 if(this.collapsed){
36040 return this.collapsedEl.getBox();
36042 var box = this.el.getBox();
36044 var sh = this.split.el.getHeight();
36051 updateBox : function(box){
36052 if(this.split && !this.collapsed){
36053 var sh = this.split.el.getHeight();
36056 this.split.el.setLeft(box.x);
36057 this.split.el.setTop(box.y-sh);
36058 this.split.el.setWidth(box.width);
36060 if(this.collapsed){
36061 this.updateBody(box.width, null);
36063 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36067 Roo.bootstrap.layout.East = function(config){
36068 config.region = "east";
36069 config.cursor = "e-resize";
36070 Roo.bootstrap.layout.Split.call(this, config);
36072 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36073 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36074 this.split.el.addClass("roo-layout-split-h");
36076 var size = config.initialSize || config.width;
36077 if(typeof size != "undefined"){
36078 this.el.setWidth(size);
36081 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36082 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36083 getBox : function(){
36084 if(this.collapsed){
36085 return this.collapsedEl.getBox();
36087 var box = this.el.getBox();
36089 var sw = this.split.el.getWidth();
36096 updateBox : function(box){
36097 if(this.split && !this.collapsed){
36098 var sw = this.split.el.getWidth();
36100 this.split.el.setLeft(box.x);
36101 this.split.el.setTop(box.y);
36102 this.split.el.setHeight(box.height);
36105 if(this.collapsed){
36106 this.updateBody(null, box.height);
36108 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36112 Roo.bootstrap.layout.West = function(config){
36113 config.region = "west";
36114 config.cursor = "w-resize";
36116 Roo.bootstrap.layout.Split.call(this, config);
36118 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36119 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36120 this.split.el.addClass("roo-layout-split-h");
36124 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36125 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36127 onRender: function(ctr, pos)
36129 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36130 var size = this.config.initialSize || this.config.width;
36131 if(typeof size != "undefined"){
36132 this.el.setWidth(size);
36136 getBox : function(){
36137 if(this.collapsed){
36138 return this.collapsedEl.getBox();
36140 var box = this.el.getBox();
36142 box.width += this.split.el.getWidth();
36147 updateBox : function(box){
36148 if(this.split && !this.collapsed){
36149 var sw = this.split.el.getWidth();
36151 this.split.el.setLeft(box.x+box.width);
36152 this.split.el.setTop(box.y);
36153 this.split.el.setHeight(box.height);
36155 if(this.collapsed){
36156 this.updateBody(null, box.height);
36158 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36161 Roo.namespace("Roo.bootstrap.panel");/*
36163 * Ext JS Library 1.1.1
36164 * Copyright(c) 2006-2007, Ext JS, LLC.
36166 * Originally Released Under LGPL - original licence link has changed is not relivant.
36169 * <script type="text/javascript">
36172 * @class Roo.ContentPanel
36173 * @extends Roo.util.Observable
36174 * A basic ContentPanel element.
36175 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36176 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36177 * @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
36178 * @cfg {Boolean} closable True if the panel can be closed/removed
36179 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36180 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36181 * @cfg {Toolbar} toolbar A toolbar for this panel
36182 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36183 * @cfg {String} title The title for this panel
36184 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36185 * @cfg {String} url Calls {@link #setUrl} with this value
36186 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36187 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36188 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36189 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36190 * @cfg {Boolean} badges render the badges
36193 * Create a new ContentPanel.
36194 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36195 * @param {String/Object} config A string to set only the title or a config object
36196 * @param {String} content (optional) Set the HTML content for this panel
36197 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36199 Roo.bootstrap.panel.Content = function( config){
36201 this.tpl = config.tpl || false;
36203 var el = config.el;
36204 var content = config.content;
36206 if(config.autoCreate){ // xtype is available if this is called from factory
36209 this.el = Roo.get(el);
36210 if(!this.el && config && config.autoCreate){
36211 if(typeof config.autoCreate == "object"){
36212 if(!config.autoCreate.id){
36213 config.autoCreate.id = config.id||el;
36215 this.el = Roo.DomHelper.append(document.body,
36216 config.autoCreate, true);
36218 var elcfg = { tag: "div",
36219 cls: "roo-layout-inactive-content",
36223 elcfg.html = config.html;
36227 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36230 this.closable = false;
36231 this.loaded = false;
36232 this.active = false;
36235 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36237 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36239 this.wrapEl = this.el; //this.el.wrap();
36241 if (config.toolbar.items) {
36242 ti = config.toolbar.items ;
36243 delete config.toolbar.items ;
36247 this.toolbar.render(this.wrapEl, 'before');
36248 for(var i =0;i < ti.length;i++) {
36249 // Roo.log(['add child', items[i]]);
36250 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36252 this.toolbar.items = nitems;
36253 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36254 delete config.toolbar;
36258 // xtype created footer. - not sure if will work as we normally have to render first..
36259 if (this.footer && !this.footer.el && this.footer.xtype) {
36260 if (!this.wrapEl) {
36261 this.wrapEl = this.el.wrap();
36264 this.footer.container = this.wrapEl.createChild();
36266 this.footer = Roo.factory(this.footer, Roo);
36271 if(typeof config == "string"){
36272 this.title = config;
36274 Roo.apply(this, config);
36278 this.resizeEl = Roo.get(this.resizeEl, true);
36280 this.resizeEl = this.el;
36282 // handle view.xtype
36290 * Fires when this panel is activated.
36291 * @param {Roo.ContentPanel} this
36295 * @event deactivate
36296 * Fires when this panel is activated.
36297 * @param {Roo.ContentPanel} this
36299 "deactivate" : true,
36303 * Fires when this panel is resized if fitToFrame is true.
36304 * @param {Roo.ContentPanel} this
36305 * @param {Number} width The width after any component adjustments
36306 * @param {Number} height The height after any component adjustments
36312 * Fires when this tab is created
36313 * @param {Roo.ContentPanel} this
36324 if(this.autoScroll){
36325 this.resizeEl.setStyle("overflow", "auto");
36327 // fix randome scrolling
36328 //this.el.on('scroll', function() {
36329 // Roo.log('fix random scolling');
36330 // this.scrollTo('top',0);
36333 content = content || this.content;
36335 this.setContent(content);
36337 if(config && config.url){
36338 this.setUrl(this.url, this.params, this.loadOnce);
36343 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36345 if (this.view && typeof(this.view.xtype) != 'undefined') {
36346 this.view.el = this.el.appendChild(document.createElement("div"));
36347 this.view = Roo.factory(this.view);
36348 this.view.render && this.view.render(false, '');
36352 this.fireEvent('render', this);
36355 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36359 setRegion : function(region){
36360 this.region = region;
36361 this.setActiveClass(region && !this.background);
36365 setActiveClass: function(state)
36368 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36369 this.el.setStyle('position','relative');
36371 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36372 this.el.setStyle('position', 'absolute');
36377 * Returns the toolbar for this Panel if one was configured.
36378 * @return {Roo.Toolbar}
36380 getToolbar : function(){
36381 return this.toolbar;
36384 setActiveState : function(active)
36386 this.active = active;
36387 this.setActiveClass(active);
36389 this.fireEvent("deactivate", this);
36391 this.fireEvent("activate", this);
36395 * Updates this panel's element
36396 * @param {String} content The new content
36397 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36399 setContent : function(content, loadScripts){
36400 this.el.update(content, loadScripts);
36403 ignoreResize : function(w, h){
36404 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36407 this.lastSize = {width: w, height: h};
36412 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36413 * @return {Roo.UpdateManager} The UpdateManager
36415 getUpdateManager : function(){
36416 return this.el.getUpdateManager();
36419 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36420 * @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:
36423 url: "your-url.php",
36424 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36425 callback: yourFunction,
36426 scope: yourObject, //(optional scope)
36429 text: "Loading...",
36434 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36435 * 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.
36436 * @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}
36437 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36438 * @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.
36439 * @return {Roo.ContentPanel} this
36442 var um = this.el.getUpdateManager();
36443 um.update.apply(um, arguments);
36449 * 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.
36450 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36451 * @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)
36452 * @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)
36453 * @return {Roo.UpdateManager} The UpdateManager
36455 setUrl : function(url, params, loadOnce){
36456 if(this.refreshDelegate){
36457 this.removeListener("activate", this.refreshDelegate);
36459 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36460 this.on("activate", this.refreshDelegate);
36461 return this.el.getUpdateManager();
36464 _handleRefresh : function(url, params, loadOnce){
36465 if(!loadOnce || !this.loaded){
36466 var updater = this.el.getUpdateManager();
36467 updater.update(url, params, this._setLoaded.createDelegate(this));
36471 _setLoaded : function(){
36472 this.loaded = true;
36476 * Returns this panel's id
36479 getId : function(){
36484 * Returns this panel's element - used by regiosn to add.
36485 * @return {Roo.Element}
36487 getEl : function(){
36488 return this.wrapEl || this.el;
36493 adjustForComponents : function(width, height)
36495 //Roo.log('adjustForComponents ');
36496 if(this.resizeEl != this.el){
36497 width -= this.el.getFrameWidth('lr');
36498 height -= this.el.getFrameWidth('tb');
36501 var te = this.toolbar.getEl();
36502 te.setWidth(width);
36503 height -= te.getHeight();
36506 var te = this.footer.getEl();
36507 te.setWidth(width);
36508 height -= te.getHeight();
36512 if(this.adjustments){
36513 width += this.adjustments[0];
36514 height += this.adjustments[1];
36516 return {"width": width, "height": height};
36519 setSize : function(width, height){
36520 if(this.fitToFrame && !this.ignoreResize(width, height)){
36521 if(this.fitContainer && this.resizeEl != this.el){
36522 this.el.setSize(width, height);
36524 var size = this.adjustForComponents(width, height);
36525 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36526 this.fireEvent('resize', this, size.width, size.height);
36531 * Returns this panel's title
36534 getTitle : function(){
36536 if (typeof(this.title) != 'object') {
36541 for (var k in this.title) {
36542 if (!this.title.hasOwnProperty(k)) {
36546 if (k.indexOf('-') >= 0) {
36547 var s = k.split('-');
36548 for (var i = 0; i<s.length; i++) {
36549 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36552 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36559 * Set this panel's title
36560 * @param {String} title
36562 setTitle : function(title){
36563 this.title = title;
36565 this.region.updatePanelTitle(this, title);
36570 * Returns true is this panel was configured to be closable
36571 * @return {Boolean}
36573 isClosable : function(){
36574 return this.closable;
36577 beforeSlide : function(){
36579 this.resizeEl.clip();
36582 afterSlide : function(){
36584 this.resizeEl.unclip();
36588 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36589 * Will fail silently if the {@link #setUrl} method has not been called.
36590 * This does not activate the panel, just updates its content.
36592 refresh : function(){
36593 if(this.refreshDelegate){
36594 this.loaded = false;
36595 this.refreshDelegate();
36600 * Destroys this panel
36602 destroy : function(){
36603 this.el.removeAllListeners();
36604 var tempEl = document.createElement("span");
36605 tempEl.appendChild(this.el.dom);
36606 tempEl.innerHTML = "";
36612 * form - if the content panel contains a form - this is a reference to it.
36613 * @type {Roo.form.Form}
36617 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36618 * This contains a reference to it.
36624 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36634 * @param {Object} cfg Xtype definition of item to add.
36638 getChildContainer: function () {
36639 return this.getEl();
36644 var ret = new Roo.factory(cfg);
36649 if (cfg.xtype.match(/^Form$/)) {
36652 //if (this.footer) {
36653 // el = this.footer.container.insertSibling(false, 'before');
36655 el = this.el.createChild();
36658 this.form = new Roo.form.Form(cfg);
36661 if ( this.form.allItems.length) {
36662 this.form.render(el.dom);
36666 // should only have one of theses..
36667 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36668 // views.. should not be just added - used named prop 'view''
36670 cfg.el = this.el.appendChild(document.createElement("div"));
36673 var ret = new Roo.factory(cfg);
36675 ret.render && ret.render(false, ''); // render blank..
36685 * @class Roo.bootstrap.panel.Grid
36686 * @extends Roo.bootstrap.panel.Content
36688 * Create a new GridPanel.
36689 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36690 * @param {Object} config A the config object
36696 Roo.bootstrap.panel.Grid = function(config)
36700 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36701 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36703 config.el = this.wrapper;
36704 //this.el = this.wrapper;
36706 if (config.container) {
36707 // ctor'ed from a Border/panel.grid
36710 this.wrapper.setStyle("overflow", "hidden");
36711 this.wrapper.addClass('roo-grid-container');
36716 if(config.toolbar){
36717 var tool_el = this.wrapper.createChild();
36718 this.toolbar = Roo.factory(config.toolbar);
36720 if (config.toolbar.items) {
36721 ti = config.toolbar.items ;
36722 delete config.toolbar.items ;
36726 this.toolbar.render(tool_el);
36727 for(var i =0;i < ti.length;i++) {
36728 // Roo.log(['add child', items[i]]);
36729 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36731 this.toolbar.items = nitems;
36733 delete config.toolbar;
36736 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36737 config.grid.scrollBody = true;;
36738 config.grid.monitorWindowResize = false; // turn off autosizing
36739 config.grid.autoHeight = false;
36740 config.grid.autoWidth = false;
36742 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36744 if (config.background) {
36745 // render grid on panel activation (if panel background)
36746 this.on('activate', function(gp) {
36747 if (!gp.grid.rendered) {
36748 gp.grid.render(this.wrapper);
36749 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36754 this.grid.render(this.wrapper);
36755 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36758 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36759 // ??? needed ??? config.el = this.wrapper;
36764 // xtype created footer. - not sure if will work as we normally have to render first..
36765 if (this.footer && !this.footer.el && this.footer.xtype) {
36767 var ctr = this.grid.getView().getFooterPanel(true);
36768 this.footer.dataSource = this.grid.dataSource;
36769 this.footer = Roo.factory(this.footer, Roo);
36770 this.footer.render(ctr);
36780 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36781 getId : function(){
36782 return this.grid.id;
36786 * Returns the grid for this panel
36787 * @return {Roo.bootstrap.Table}
36789 getGrid : function(){
36793 setSize : function(width, height){
36794 if(!this.ignoreResize(width, height)){
36795 var grid = this.grid;
36796 var size = this.adjustForComponents(width, height);
36797 var gridel = grid.getGridEl();
36798 gridel.setSize(size.width, size.height);
36800 var thd = grid.getGridEl().select('thead',true).first();
36801 var tbd = grid.getGridEl().select('tbody', true).first();
36803 tbd.setSize(width, height - thd.getHeight());
36812 beforeSlide : function(){
36813 this.grid.getView().scroller.clip();
36816 afterSlide : function(){
36817 this.grid.getView().scroller.unclip();
36820 destroy : function(){
36821 this.grid.destroy();
36823 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36828 * @class Roo.bootstrap.panel.Nest
36829 * @extends Roo.bootstrap.panel.Content
36831 * Create a new Panel, that can contain a layout.Border.
36834 * @param {Roo.BorderLayout} layout The layout for this panel
36835 * @param {String/Object} config A string to set only the title or a config object
36837 Roo.bootstrap.panel.Nest = function(config)
36839 // construct with only one argument..
36840 /* FIXME - implement nicer consturctors
36841 if (layout.layout) {
36843 layout = config.layout;
36844 delete config.layout;
36846 if (layout.xtype && !layout.getEl) {
36847 // then layout needs constructing..
36848 layout = Roo.factory(layout, Roo);
36852 config.el = config.layout.getEl();
36854 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36856 config.layout.monitorWindowResize = false; // turn off autosizing
36857 this.layout = config.layout;
36858 this.layout.getEl().addClass("roo-layout-nested-layout");
36865 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36867 setSize : function(width, height){
36868 if(!this.ignoreResize(width, height)){
36869 var size = this.adjustForComponents(width, height);
36870 var el = this.layout.getEl();
36871 if (size.height < 1) {
36872 el.setWidth(size.width);
36874 el.setSize(size.width, size.height);
36876 var touch = el.dom.offsetWidth;
36877 this.layout.layout();
36878 // ie requires a double layout on the first pass
36879 if(Roo.isIE && !this.initialized){
36880 this.initialized = true;
36881 this.layout.layout();
36886 // activate all subpanels if not currently active..
36888 setActiveState : function(active){
36889 this.active = active;
36890 this.setActiveClass(active);
36893 this.fireEvent("deactivate", this);
36897 this.fireEvent("activate", this);
36898 // not sure if this should happen before or after..
36899 if (!this.layout) {
36900 return; // should not happen..
36903 for (var r in this.layout.regions) {
36904 reg = this.layout.getRegion(r);
36905 if (reg.getActivePanel()) {
36906 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36907 reg.setActivePanel(reg.getActivePanel());
36910 if (!reg.panels.length) {
36913 reg.showPanel(reg.getPanel(0));
36922 * Returns the nested BorderLayout for this panel
36923 * @return {Roo.BorderLayout}
36925 getLayout : function(){
36926 return this.layout;
36930 * Adds a xtype elements to the layout of the nested panel
36934 xtype : 'ContentPanel',
36941 xtype : 'NestedLayoutPanel',
36947 items : [ ... list of content panels or nested layout panels.. ]
36951 * @param {Object} cfg Xtype definition of item to add.
36953 addxtype : function(cfg) {
36954 return this.layout.addxtype(cfg);
36959 * Ext JS Library 1.1.1
36960 * Copyright(c) 2006-2007, Ext JS, LLC.
36962 * Originally Released Under LGPL - original licence link has changed is not relivant.
36965 * <script type="text/javascript">
36968 * @class Roo.TabPanel
36969 * @extends Roo.util.Observable
36970 * A lightweight tab container.
36974 // basic tabs 1, built from existing content
36975 var tabs = new Roo.TabPanel("tabs1");
36976 tabs.addTab("script", "View Script");
36977 tabs.addTab("markup", "View Markup");
36978 tabs.activate("script");
36980 // more advanced tabs, built from javascript
36981 var jtabs = new Roo.TabPanel("jtabs");
36982 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36984 // set up the UpdateManager
36985 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36986 var updater = tab2.getUpdateManager();
36987 updater.setDefaultUrl("ajax1.htm");
36988 tab2.on('activate', updater.refresh, updater, true);
36990 // Use setUrl for Ajax loading
36991 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36992 tab3.setUrl("ajax2.htm", null, true);
36995 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36998 jtabs.activate("jtabs-1");
37001 * Create a new TabPanel.
37002 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37003 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37005 Roo.bootstrap.panel.Tabs = function(config){
37007 * The container element for this TabPanel.
37008 * @type Roo.Element
37010 this.el = Roo.get(config.el);
37013 if(typeof config == "boolean"){
37014 this.tabPosition = config ? "bottom" : "top";
37016 Roo.apply(this, config);
37020 if(this.tabPosition == "bottom"){
37021 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37022 this.el.addClass("roo-tabs-bottom");
37024 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37025 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37026 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37028 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37030 if(this.tabPosition != "bottom"){
37031 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37032 * @type Roo.Element
37034 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37035 this.el.addClass("roo-tabs-top");
37039 this.bodyEl.setStyle("position", "relative");
37041 this.active = null;
37042 this.activateDelegate = this.activate.createDelegate(this);
37047 * Fires when the active tab changes
37048 * @param {Roo.TabPanel} this
37049 * @param {Roo.TabPanelItem} activePanel The new active tab
37053 * @event beforetabchange
37054 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37055 * @param {Roo.TabPanel} this
37056 * @param {Object} e Set cancel to true on this object to cancel the tab change
37057 * @param {Roo.TabPanelItem} tab The tab being changed to
37059 "beforetabchange" : true
37062 Roo.EventManager.onWindowResize(this.onResize, this);
37063 this.cpad = this.el.getPadding("lr");
37064 this.hiddenCount = 0;
37067 // toolbar on the tabbar support...
37068 if (this.toolbar) {
37069 alert("no toolbar support yet");
37070 this.toolbar = false;
37072 var tcfg = this.toolbar;
37073 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37074 this.toolbar = new Roo.Toolbar(tcfg);
37075 if (Roo.isSafari) {
37076 var tbl = tcfg.container.child('table', true);
37077 tbl.setAttribute('width', '100%');
37085 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37088 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37090 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37092 tabPosition : "top",
37094 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37096 currentTabWidth : 0,
37098 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37102 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37106 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37108 preferredTabWidth : 175,
37110 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37112 resizeTabs : false,
37114 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37116 monitorResize : true,
37118 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37123 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37124 * @param {String} id The id of the div to use <b>or create</b>
37125 * @param {String} text The text for the tab
37126 * @param {String} content (optional) Content to put in the TabPanelItem body
37127 * @param {Boolean} closable (optional) True to create a close icon on the tab
37128 * @return {Roo.TabPanelItem} The created TabPanelItem
37130 addTab : function(id, text, content, closable, tpl)
37132 var item = new Roo.bootstrap.panel.TabItem({
37136 closable : closable,
37139 this.addTabItem(item);
37141 item.setContent(content);
37147 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37148 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37149 * @return {Roo.TabPanelItem}
37151 getTab : function(id){
37152 return this.items[id];
37156 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37157 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37159 hideTab : function(id){
37160 var t = this.items[id];
37163 this.hiddenCount++;
37164 this.autoSizeTabs();
37169 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37170 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37172 unhideTab : function(id){
37173 var t = this.items[id];
37175 t.setHidden(false);
37176 this.hiddenCount--;
37177 this.autoSizeTabs();
37182 * Adds an existing {@link Roo.TabPanelItem}.
37183 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37185 addTabItem : function(item){
37186 this.items[item.id] = item;
37187 this.items.push(item);
37188 // if(this.resizeTabs){
37189 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37190 // this.autoSizeTabs();
37192 // item.autoSize();
37197 * Removes a {@link Roo.TabPanelItem}.
37198 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37200 removeTab : function(id){
37201 var items = this.items;
37202 var tab = items[id];
37203 if(!tab) { return; }
37204 var index = items.indexOf(tab);
37205 if(this.active == tab && items.length > 1){
37206 var newTab = this.getNextAvailable(index);
37211 this.stripEl.dom.removeChild(tab.pnode.dom);
37212 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37213 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37215 items.splice(index, 1);
37216 delete this.items[tab.id];
37217 tab.fireEvent("close", tab);
37218 tab.purgeListeners();
37219 this.autoSizeTabs();
37222 getNextAvailable : function(start){
37223 var items = this.items;
37225 // look for a next tab that will slide over to
37226 // replace the one being removed
37227 while(index < items.length){
37228 var item = items[++index];
37229 if(item && !item.isHidden()){
37233 // if one isn't found select the previous tab (on the left)
37236 var item = items[--index];
37237 if(item && !item.isHidden()){
37245 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37246 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37248 disableTab : function(id){
37249 var tab = this.items[id];
37250 if(tab && this.active != tab){
37256 * Enables a {@link Roo.TabPanelItem} that is disabled.
37257 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37259 enableTab : function(id){
37260 var tab = this.items[id];
37265 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37266 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37267 * @return {Roo.TabPanelItem} The TabPanelItem.
37269 activate : function(id){
37270 var tab = this.items[id];
37274 if(tab == this.active || tab.disabled){
37278 this.fireEvent("beforetabchange", this, e, tab);
37279 if(e.cancel !== true && !tab.disabled){
37281 this.active.hide();
37283 this.active = this.items[id];
37284 this.active.show();
37285 this.fireEvent("tabchange", this, this.active);
37291 * Gets the active {@link Roo.TabPanelItem}.
37292 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37294 getActiveTab : function(){
37295 return this.active;
37299 * Updates the tab body element to fit the height of the container element
37300 * for overflow scrolling
37301 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37303 syncHeight : function(targetHeight){
37304 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37305 var bm = this.bodyEl.getMargins();
37306 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37307 this.bodyEl.setHeight(newHeight);
37311 onResize : function(){
37312 if(this.monitorResize){
37313 this.autoSizeTabs();
37318 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37320 beginUpdate : function(){
37321 this.updating = true;
37325 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37327 endUpdate : function(){
37328 this.updating = false;
37329 this.autoSizeTabs();
37333 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37335 autoSizeTabs : function(){
37336 var count = this.items.length;
37337 var vcount = count - this.hiddenCount;
37338 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37341 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37342 var availWidth = Math.floor(w / vcount);
37343 var b = this.stripBody;
37344 if(b.getWidth() > w){
37345 var tabs = this.items;
37346 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37347 if(availWidth < this.minTabWidth){
37348 /*if(!this.sleft){ // incomplete scrolling code
37349 this.createScrollButtons();
37352 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37355 if(this.currentTabWidth < this.preferredTabWidth){
37356 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37362 * Returns the number of tabs in this TabPanel.
37365 getCount : function(){
37366 return this.items.length;
37370 * Resizes all the tabs to the passed width
37371 * @param {Number} The new width
37373 setTabWidth : function(width){
37374 this.currentTabWidth = width;
37375 for(var i = 0, len = this.items.length; i < len; i++) {
37376 if(!this.items[i].isHidden()) {
37377 this.items[i].setWidth(width);
37383 * Destroys this TabPanel
37384 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37386 destroy : function(removeEl){
37387 Roo.EventManager.removeResizeListener(this.onResize, this);
37388 for(var i = 0, len = this.items.length; i < len; i++){
37389 this.items[i].purgeListeners();
37391 if(removeEl === true){
37392 this.el.update("");
37397 createStrip : function(container)
37399 var strip = document.createElement("nav");
37400 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37401 container.appendChild(strip);
37405 createStripList : function(strip)
37407 // div wrapper for retard IE
37408 // returns the "tr" element.
37409 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37410 //'<div class="x-tabs-strip-wrap">'+
37411 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37412 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37413 return strip.firstChild; //.firstChild.firstChild.firstChild;
37415 createBody : function(container)
37417 var body = document.createElement("div");
37418 Roo.id(body, "tab-body");
37419 //Roo.fly(body).addClass("x-tabs-body");
37420 Roo.fly(body).addClass("tab-content");
37421 container.appendChild(body);
37424 createItemBody :function(bodyEl, id){
37425 var body = Roo.getDom(id);
37427 body = document.createElement("div");
37430 //Roo.fly(body).addClass("x-tabs-item-body");
37431 Roo.fly(body).addClass("tab-pane");
37432 bodyEl.insertBefore(body, bodyEl.firstChild);
37436 createStripElements : function(stripEl, text, closable, tpl)
37438 var td = document.createElement("li"); // was td..
37441 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37444 stripEl.appendChild(td);
37446 td.className = "x-tabs-closable";
37447 if(!this.closeTpl){
37448 this.closeTpl = new Roo.Template(
37449 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37450 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37451 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37454 var el = this.closeTpl.overwrite(td, {"text": text});
37455 var close = el.getElementsByTagName("div")[0];
37456 var inner = el.getElementsByTagName("em")[0];
37457 return {"el": el, "close": close, "inner": inner};
37460 // not sure what this is..
37461 // if(!this.tabTpl){
37462 //this.tabTpl = new Roo.Template(
37463 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37464 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37466 // this.tabTpl = new Roo.Template(
37467 // '<a href="#">' +
37468 // '<span unselectable="on"' +
37469 // (this.disableTooltips ? '' : ' title="{text}"') +
37470 // ' >{text}</span></a>'
37476 var template = tpl || this.tabTpl || false;
37480 template = new Roo.Template(
37482 '<span unselectable="on"' +
37483 (this.disableTooltips ? '' : ' title="{text}"') +
37484 ' >{text}</span></a>'
37488 switch (typeof(template)) {
37492 template = new Roo.Template(template);
37498 var el = template.overwrite(td, {"text": text});
37500 var inner = el.getElementsByTagName("span")[0];
37502 return {"el": el, "inner": inner};
37510 * @class Roo.TabPanelItem
37511 * @extends Roo.util.Observable
37512 * Represents an individual item (tab plus body) in a TabPanel.
37513 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37514 * @param {String} id The id of this TabPanelItem
37515 * @param {String} text The text for the tab of this TabPanelItem
37516 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37518 Roo.bootstrap.panel.TabItem = function(config){
37520 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37521 * @type Roo.TabPanel
37523 this.tabPanel = config.panel;
37525 * The id for this TabPanelItem
37528 this.id = config.id;
37530 this.disabled = false;
37532 this.text = config.text;
37534 this.loaded = false;
37535 this.closable = config.closable;
37538 * The body element for this TabPanelItem.
37539 * @type Roo.Element
37541 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37542 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37543 this.bodyEl.setStyle("display", "block");
37544 this.bodyEl.setStyle("zoom", "1");
37545 //this.hideAction();
37547 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37549 this.el = Roo.get(els.el);
37550 this.inner = Roo.get(els.inner, true);
37551 this.textEl = Roo.get(this.el.dom.firstChild, true);
37552 this.pnode = Roo.get(els.el.parentNode, true);
37553 this.el.on("mousedown", this.onTabMouseDown, this);
37554 this.el.on("click", this.onTabClick, this);
37556 if(config.closable){
37557 var c = Roo.get(els.close, true);
37558 c.dom.title = this.closeText;
37559 c.addClassOnOver("close-over");
37560 c.on("click", this.closeClick, this);
37566 * Fires when this tab becomes the active tab.
37567 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37568 * @param {Roo.TabPanelItem} this
37572 * @event beforeclose
37573 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37574 * @param {Roo.TabPanelItem} this
37575 * @param {Object} e Set cancel to true on this object to cancel the close.
37577 "beforeclose": true,
37580 * Fires when this tab is closed.
37581 * @param {Roo.TabPanelItem} this
37585 * @event deactivate
37586 * Fires when this tab is no longer the active tab.
37587 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37588 * @param {Roo.TabPanelItem} this
37590 "deactivate" : true
37592 this.hidden = false;
37594 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37597 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37599 purgeListeners : function(){
37600 Roo.util.Observable.prototype.purgeListeners.call(this);
37601 this.el.removeAllListeners();
37604 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37607 this.pnode.addClass("active");
37610 this.tabPanel.stripWrap.repaint();
37612 this.fireEvent("activate", this.tabPanel, this);
37616 * Returns true if this tab is the active tab.
37617 * @return {Boolean}
37619 isActive : function(){
37620 return this.tabPanel.getActiveTab() == this;
37624 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37627 this.pnode.removeClass("active");
37629 this.fireEvent("deactivate", this.tabPanel, this);
37632 hideAction : function(){
37633 this.bodyEl.hide();
37634 this.bodyEl.setStyle("position", "absolute");
37635 this.bodyEl.setLeft("-20000px");
37636 this.bodyEl.setTop("-20000px");
37639 showAction : function(){
37640 this.bodyEl.setStyle("position", "relative");
37641 this.bodyEl.setTop("");
37642 this.bodyEl.setLeft("");
37643 this.bodyEl.show();
37647 * Set the tooltip for the tab.
37648 * @param {String} tooltip The tab's tooltip
37650 setTooltip : function(text){
37651 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37652 this.textEl.dom.qtip = text;
37653 this.textEl.dom.removeAttribute('title');
37655 this.textEl.dom.title = text;
37659 onTabClick : function(e){
37660 e.preventDefault();
37661 this.tabPanel.activate(this.id);
37664 onTabMouseDown : function(e){
37665 e.preventDefault();
37666 this.tabPanel.activate(this.id);
37669 getWidth : function(){
37670 return this.inner.getWidth();
37673 setWidth : function(width){
37674 var iwidth = width - this.pnode.getPadding("lr");
37675 this.inner.setWidth(iwidth);
37676 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37677 this.pnode.setWidth(width);
37681 * Show or hide the tab
37682 * @param {Boolean} hidden True to hide or false to show.
37684 setHidden : function(hidden){
37685 this.hidden = hidden;
37686 this.pnode.setStyle("display", hidden ? "none" : "");
37690 * Returns true if this tab is "hidden"
37691 * @return {Boolean}
37693 isHidden : function(){
37694 return this.hidden;
37698 * Returns the text for this tab
37701 getText : function(){
37705 autoSize : function(){
37706 //this.el.beginMeasure();
37707 this.textEl.setWidth(1);
37709 * #2804 [new] Tabs in Roojs
37710 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37712 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37713 //this.el.endMeasure();
37717 * Sets the text for the tab (Note: this also sets the tooltip text)
37718 * @param {String} text The tab's text and tooltip
37720 setText : function(text){
37722 this.textEl.update(text);
37723 this.setTooltip(text);
37724 //if(!this.tabPanel.resizeTabs){
37725 // this.autoSize();
37729 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37731 activate : function(){
37732 this.tabPanel.activate(this.id);
37736 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37738 disable : function(){
37739 if(this.tabPanel.active != this){
37740 this.disabled = true;
37741 this.pnode.addClass("disabled");
37746 * Enables this TabPanelItem if it was previously disabled.
37748 enable : function(){
37749 this.disabled = false;
37750 this.pnode.removeClass("disabled");
37754 * Sets the content for this TabPanelItem.
37755 * @param {String} content The content
37756 * @param {Boolean} loadScripts true to look for and load scripts
37758 setContent : function(content, loadScripts){
37759 this.bodyEl.update(content, loadScripts);
37763 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37764 * @return {Roo.UpdateManager} The UpdateManager
37766 getUpdateManager : function(){
37767 return this.bodyEl.getUpdateManager();
37771 * Set a URL to be used to load the content for this TabPanelItem.
37772 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37773 * @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)
37774 * @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)
37775 * @return {Roo.UpdateManager} The UpdateManager
37777 setUrl : function(url, params, loadOnce){
37778 if(this.refreshDelegate){
37779 this.un('activate', this.refreshDelegate);
37781 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37782 this.on("activate", this.refreshDelegate);
37783 return this.bodyEl.getUpdateManager();
37787 _handleRefresh : function(url, params, loadOnce){
37788 if(!loadOnce || !this.loaded){
37789 var updater = this.bodyEl.getUpdateManager();
37790 updater.update(url, params, this._setLoaded.createDelegate(this));
37795 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37796 * Will fail silently if the setUrl method has not been called.
37797 * This does not activate the panel, just updates its content.
37799 refresh : function(){
37800 if(this.refreshDelegate){
37801 this.loaded = false;
37802 this.refreshDelegate();
37807 _setLoaded : function(){
37808 this.loaded = true;
37812 closeClick : function(e){
37815 this.fireEvent("beforeclose", this, o);
37816 if(o.cancel !== true){
37817 this.tabPanel.removeTab(this.id);
37821 * The text displayed in the tooltip for the close icon.
37824 closeText : "Close this tab"
37834 * @class Roo.bootstrap.PhoneInput
37835 * @extends Roo.bootstrap.TriggerField
37836 * Bootstrap PhoneInput class
37839 * Create a new PhoneInput
37840 * @param {Object} config The config object
37843 Roo.bootstrap.PhoneInput = function(config){
37844 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
37849 //setting global...
37851 this.tickItems = [];
37853 this.selectedIndex = -1;
37854 if(this.mode == 'local'){
37855 if(config.queryDelay === undefined){
37856 this.queryDelay = 10;
37858 if(config.minChars === undefined){
37864 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
37866 //setting properties..
37868 getAutoCreate : function()
37873 * Render classic select for iso
37876 if(Roo.isIOS && this.useNativeIOS){
37877 cfg = this.getAutoCreateNativeIOS();
37885 if(Roo.isTouch && this.mobileTouchView){
37886 cfg = this.getAutoCreateTouchView();
37891 * Normal PhoneInput
37893 if(!this.tickable){
37894 cfg = Roo.bootstrap.PhoneInput.superclass.getAutoCreate.call(this);
37895 if(this.name == 'info_year_invest_id_display_name'){
37896 Roo.log('cfg.................................................');
37903 * PhoneInput with tickable selections
37906 var align = this.labelAlign || this.parentLabelAlign();
37909 cls : 'form-group roo-PhoneInput-tickable' //input-group
37912 var btn_text_select = '';
37913 var btn_text_done = '';
37914 var btn_text_cancel = '';
37916 if (this.btn_text_show) {
37917 btn_text_select = 'Select';
37918 btn_text_done = 'Done';
37919 btn_text_cancel = 'Cancel';
37924 cls : 'tickable-buttons',
37929 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
37930 //html : this.triggerText
37931 html: btn_text_select
37937 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
37939 html: btn_text_done
37945 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
37947 html: btn_text_cancel
37953 buttons.cn.unshift({
37955 cls: 'roo-select2-search-field-input'
37961 Roo.each(buttons.cn, function(c){
37963 c.cls += ' btn-' + _this.size;
37966 if (_this.disabled) {
37977 cls: 'form-hidden-field'
37981 cls: 'roo-select2-choices',
37985 cls: 'roo-select2-search-field',
37996 cls: 'roo-select2-container input-group roo-select2-container-multi',
38001 // cls: 'typeahead typeahead-long dropdown-menu',
38002 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
38007 if(this.hasFeedback && !this.allowBlank){
38011 cls: 'glyphicon form-control-feedback'
38014 PhoneInput.cn.push(feedback);
38018 if (align ==='left' && this.fieldLabel.length) {
38020 cfg.cls += ' roo-form-group-label-left';
38025 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
38026 tooltip : 'This field is required'
38031 cls : 'control-label',
38032 html : this.fieldLabel
38044 var labelCfg = cfg.cn[1];
38045 var contentCfg = cfg.cn[2];
38048 if(this.indicatorpos == 'right'){
38054 cls : 'control-label',
38058 html : this.fieldLabel
38062 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
38063 tooltip : 'This field is required'
38078 labelCfg = cfg.cn[0];
38079 contentCfg = cfg.cn[1];
38083 if(this.labelWidth > 12){
38084 labelCfg.style = "width: " + this.labelWidth + 'px';
38087 if(this.labelWidth < 13 && this.labelmd == 0){
38088 this.labelmd = this.labelWidth;
38091 if(this.labellg > 0){
38092 labelCfg.cls += ' col-lg-' + this.labellg;
38093 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
38096 if(this.labelmd > 0){
38097 labelCfg.cls += ' col-md-' + this.labelmd;
38098 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
38101 if(this.labelsm > 0){
38102 labelCfg.cls += ' col-sm-' + this.labelsm;
38103 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
38106 if(this.labelxs > 0){
38107 labelCfg.cls += ' col-xs-' + this.labelxs;
38108 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
38112 } else if ( this.fieldLabel.length) {
38113 // Roo.log(" label");
38117 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
38118 tooltip : 'This field is required'
38122 //cls : 'input-group-addon',
38123 html : this.fieldLabel
38128 if(this.indicatorpos == 'right'){
38129 Roo.log('hidden name:'+this.hiddenName);
38133 //cls : 'input-group-addon',
38134 html : this.fieldLabel
38138 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
38139 tooltip : 'This field is required'
38148 // Roo.log(" no label && no align");
38155 ['xs','sm','md','lg'].map(function(size){
38156 if (settings[size]) {
38157 cfg.cls += ' col-' + size + '-' + settings[size];
38165 _initEventsCalled : false,
38168 initEvents: function()
38170 if (this._initEventsCalled) { // as we call render... prevent looping...
38173 this._initEventsCalled = true;
38176 throw "can not find store for combo";
38179 this.store = Roo.factory(this.store, Roo.data);
38180 this.store.parent = this;
38182 // if we are building from html. then this element is so complex, that we can not really
38183 // use the rendered HTML.
38184 // so we have to trash and replace the previous code.
38185 if (Roo.XComponent.build_from_html) {
38187 // remove this element....
38188 var e = this.el.dom, k=0;
38189 while (e ) { e = e.previousSibling; ++k;}
38194 this.rendered = false;
38196 this.render(this.parent().getChildContainer(true), k);
38202 if(Roo.isIOS && this.useNativeIOS){
38203 this.initIOSView();
38211 if(Roo.isTouch && this.mobileTouchView){
38212 this.initTouchView();
38217 this.initTickableEvents();
38221 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
38223 if(this.hiddenName){
38225 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
38227 this.hiddenField.dom.value =
38228 this.hiddenValue !== undefined ? this.hiddenValue :
38229 this.value !== undefined ? this.value : '';
38231 // prevent input submission
38232 this.el.dom.removeAttribute('name');
38233 this.hiddenField.dom.setAttribute('name', this.hiddenName);
38238 // this.el.dom.setAttribute('autocomplete', 'off');
38241 var cls = 'x-combo-list';
38243 //this.list = new Roo.Layer({
38244 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
38250 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
38251 _this.list.setWidth(lw);
38254 this.list.on('mouseover', this.onViewOver, this);
38255 this.list.on('mousemove', this.onViewMove, this);
38257 this.list.on('scroll', this.onViewScroll, this);
38260 this.list.swallowEvent('mousewheel');
38261 this.assetHeight = 0;
38264 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
38265 this.assetHeight += this.header.getHeight();
38268 this.innerList = this.list.createChild({cls:cls+'-inner'});
38269 this.innerList.on('mouseover', this.onViewOver, this);
38270 this.innerList.on('mousemove', this.onViewMove, this);
38271 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38273 if(this.allowBlank && !this.pageSize && !this.disableClear){
38274 this.footer = this.list.createChild({cls:cls+'-ft'});
38275 this.pageTb = new Roo.Toolbar(this.footer);
38279 this.footer = this.list.createChild({cls:cls+'-ft'});
38280 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
38281 {pageSize: this.pageSize});
38285 if (this.pageTb && this.allowBlank && !this.disableClear) {
38287 this.pageTb.add(new Roo.Toolbar.Fill(), {
38288 cls: 'x-btn-icon x-btn-clear',
38290 handler: function()
38293 _this.clearValue();
38294 _this.onSelect(false, -1);
38299 this.assetHeight += this.footer.getHeight();
38304 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
38307 this.view = new Roo.View(this.list, this.tpl, {
38308 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38310 //this.view.wrapEl.setDisplayed(false);
38311 this.view.on('click', this.onViewClick, this);
38314 this.store.on('beforeload', this.onBeforeLoad, this);
38315 this.store.on('load', this.onLoad, this);
38316 this.store.on('loadexception', this.onLoadException, this);
38318 if(this.resizable){
38319 this.resizer = new Roo.Resizable(this.list, {
38320 pinned:true, handles:'se'
38322 this.resizer.on('resize', function(r, w, h){
38323 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
38324 this.listWidth = w;
38325 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
38326 this.restrictHeight();
38328 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
38331 if(!this.editable){
38332 this.editable = true;
38333 this.setEditable(false);
38338 if (typeof(this.events.add.listeners) != 'undefined') {
38340 this.addicon = this.wrap.createChild(
38341 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
38343 this.addicon.on('click', function(e) {
38344 this.fireEvent('add', this);
38347 if (typeof(this.events.edit.listeners) != 'undefined') {
38349 this.editicon = this.wrap.createChild(
38350 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
38351 if (this.addicon) {
38352 this.editicon.setStyle('margin-left', '40px');
38354 this.editicon.on('click', function(e) {
38356 // we fire even if inothing is selected..
38357 this.fireEvent('edit', this, this.lastData );
38363 this.keyNav = new Roo.KeyNav(this.inputEl(), {
38364 "up" : function(e){
38365 this.inKeyMode = true;
38369 "down" : function(e){
38370 if(!this.isExpanded()){
38371 this.onTriggerClick();
38373 this.inKeyMode = true;
38378 "enter" : function(e){
38379 // this.onViewClick();
38383 if(this.fireEvent("specialkey", this, e)){
38384 this.onViewClick(false);
38390 "esc" : function(e){
38394 "tab" : function(e){
38397 if(this.fireEvent("specialkey", this, e)){
38398 this.onViewClick(false);
38406 doRelay : function(foo, bar, hname){
38407 if(hname == 'down' || this.scope.isExpanded()){
38408 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38417 this.queryDelay = Math.max(this.queryDelay || 10,
38418 this.mode == 'local' ? 10 : 250);
38421 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38423 if(this.typeAhead){
38424 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38426 if(this.editable !== false){
38427 this.inputEl().on("keyup", this.onKeyUp, this);
38429 if(this.forceSelection){
38430 this.inputEl().on('blur', this.doForce, this);
38434 this.choices = this.el.select('ul.roo-select2-choices', true).first();
38435 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
38439 initTickableEvents: function()
38443 if(this.hiddenName){
38445 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
38447 this.hiddenField.dom.value =
38448 this.hiddenValue !== undefined ? this.hiddenValue :
38449 this.value !== undefined ? this.value : '';
38451 // prevent input submission
38452 this.el.dom.removeAttribute('name');
38453 this.hiddenField.dom.setAttribute('name', this.hiddenName);
38458 // this.list = this.el.select('ul.dropdown-menu',true).first();
38460 this.choices = this.el.select('ul.roo-select2-choices', true).first();
38461 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
38462 if(this.triggerList){
38463 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
38466 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
38467 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
38469 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
38470 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
38472 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
38473 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
38475 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
38476 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
38477 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
38480 this.cancelBtn.hide();
38485 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
38486 _this.list.setWidth(lw);
38489 this.list.on('mouseover', this.onViewOver, this);
38490 this.list.on('mousemove', this.onViewMove, this);
38492 this.list.on('scroll', this.onViewScroll, this);
38495 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>';
38498 this.view = new Roo.View(this.list, this.tpl, {
38499 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
38502 //this.view.wrapEl.setDisplayed(false);
38503 this.view.on('click', this.onViewClick, this);
38507 this.store.on('beforeload', this.onBeforeLoad, this);
38508 this.store.on('load', this.onLoad, this);
38509 this.store.on('loadexception', this.onLoadException, this);
38512 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
38513 "up" : function(e){
38514 this.inKeyMode = true;
38518 "down" : function(e){
38519 this.inKeyMode = true;
38523 "enter" : function(e){
38524 if(this.fireEvent("specialkey", this, e)){
38525 this.onViewClick(false);
38531 "esc" : function(e){
38532 this.onTickableFooterButtonClick(e, false, false);
38535 "tab" : function(e){
38536 this.fireEvent("specialkey", this, e);
38538 this.onTickableFooterButtonClick(e, false, false);
38545 doRelay : function(e, fn, key){
38546 if(this.scope.isExpanded()){
38547 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38556 this.queryDelay = Math.max(this.queryDelay || 10,
38557 this.mode == 'local' ? 10 : 250);
38560 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38562 if(this.typeAhead){
38563 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38566 if(this.editable !== false){
38567 this.tickableInputEl().on("keyup", this.onKeyUp, this);
38570 this.indicator = this.indicatorEl();
38572 if(this.indicator){
38573 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
38574 this.indicator.hide();
38579 onDestroy : function(){
38581 this.view.setStore(null);
38582 this.view.el.removeAllListeners();
38583 this.view.el.remove();
38584 this.view.purgeListeners();
38587 this.list.dom.innerHTML = '';
38591 this.store.un('beforeload', this.onBeforeLoad, this);
38592 this.store.un('load', this.onLoad, this);
38593 this.store.un('loadexception', this.onLoadException, this);
38595 Roo.bootstrap.PhoneInput.superclass.onDestroy.call(this);
38599 fireKey : function(e){
38600 if(e.isNavKeyPress() && !this.list.isVisible()){
38601 this.fireEvent("specialkey", this, e);
38606 onResize: function(w, h){
38607 // Roo.bootstrap.PhoneInput.superclass.onResize.apply(this, arguments);
38609 // if(typeof w != 'number'){
38610 // // we do not handle it!?!?
38613 // var tw = this.trigger.getWidth();
38614 // // tw += this.addicon ? this.addicon.getWidth() : 0;
38615 // // tw += this.editicon ? this.editicon.getWidth() : 0;
38617 // this.inputEl().setWidth( this.adjustWidth('input', x));
38619 // //this.trigger.setStyle('left', x+'px');
38621 // if(this.list && this.listWidth === undefined){
38622 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
38623 // this.list.setWidth(lw);
38624 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38632 * Allow or prevent the user from directly editing the field text. If false is passed,
38633 * the user will only be able to select from the items defined in the dropdown list. This method
38634 * is the runtime equivalent of setting the 'editable' config option at config time.
38635 * @param {Boolean} value True to allow the user to directly edit the field text
38637 setEditable : function(value){
38638 if(value == this.editable){
38641 this.editable = value;
38643 this.inputEl().dom.setAttribute('readOnly', true);
38644 this.inputEl().on('mousedown', this.onTriggerClick, this);
38645 this.inputEl().addClass('x-combo-noedit');
38647 this.inputEl().dom.setAttribute('readOnly', false);
38648 this.inputEl().un('mousedown', this.onTriggerClick, this);
38649 this.inputEl().removeClass('x-combo-noedit');
38655 onBeforeLoad : function(combo,opts){
38656 if(!this.hasFocus){
38660 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
38662 this.restrictHeight();
38663 this.selectedIndex = -1;
38667 onLoad : function(){
38669 this.hasQuery = false;
38671 if(!this.hasFocus){
38675 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
38676 this.loading.hide();
38679 if(this.store.getCount() > 0){
38682 this.restrictHeight();
38683 if(this.lastQuery == this.allQuery){
38684 if(this.editable && !this.tickable){
38685 this.inputEl().dom.select();
38689 !this.selectByValue(this.value, true) &&
38692 !this.store.lastOptions ||
38693 typeof(this.store.lastOptions.add) == 'undefined' ||
38694 this.store.lastOptions.add != true
38697 this.select(0, true);
38700 if(this.autoFocus){
38703 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
38704 this.taTask.delay(this.typeAheadDelay);
38708 this.onEmptyResults();
38714 onLoadException : function()
38716 this.hasQuery = false;
38718 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
38719 this.loading.hide();
38722 if(this.tickable && this.editable){
38727 // only causes errors at present
38728 //Roo.log(this.store.reader.jsonData);
38729 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
38731 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
38737 onTypeAhead : function(){
38738 if(this.store.getCount() > 0){
38739 var r = this.store.getAt(0);
38740 var newValue = r.data[this.displayField];
38741 var len = newValue.length;
38742 var selStart = this.getRawValue().length;
38744 if(selStart != len){
38745 this.setRawValue(newValue);
38746 this.selectText(selStart, newValue.length);
38752 onSelect : function(record, index){
38754 if(this.fireEvent('beforeselect', this, record, index) !== false){
38756 this.setFromData(index > -1 ? record.data : false);
38759 this.fireEvent('select', this, record, index);
38764 * Returns the currently selected field value or empty string if no value is set.
38765 * @return {String} value The selected value
38767 getValue : function()
38769 if(Roo.isIOS && this.useNativeIOS){
38770 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
38774 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
38777 if(this.valueField){
38778 return typeof this.value != 'undefined' ? this.value : '';
38780 return Roo.bootstrap.PhoneInput.superclass.getValue.call(this);
38784 getRawValue : function()
38786 if(Roo.isIOS && this.useNativeIOS){
38787 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
38790 var v = this.inputEl().getValue();
38796 * Clears any text/value currently set in the field
38798 clearValue : function(){
38800 if(this.hiddenField){
38801 this.hiddenField.dom.value = '';
38804 this.setRawValue('');
38805 this.lastSelectionText = '';
38806 this.lastData = false;
38808 var close = this.closeTriggerEl();
38819 * Sets the specified value into the field. If the value finds a match, the corresponding record text
38820 * will be displayed in the field. If the value does not match the data value of an existing item,
38821 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
38822 * Otherwise the field will be blank (although the value will still be set).
38823 * @param {String} value The value to match
38825 setValue : function(v)
38827 if(Roo.isIOS && this.useNativeIOS){
38828 this.setIOSValue(v);
38838 if(this.valueField){
38839 var r = this.findRecord(this.valueField, v);
38841 text = r.data[this.displayField];
38842 }else if(this.valueNotFoundText !== undefined){
38843 text = this.valueNotFoundText;
38846 this.lastSelectionText = text;
38847 if(this.hiddenField){
38848 this.hiddenField.dom.value = v;
38850 Roo.bootstrap.PhoneInput.superclass.setValue.call(this, text);
38853 var close = this.closeTriggerEl();
38856 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
38862 * @property {Object} the last set data for the element
38867 * Sets the value of the field based on a object which is related to the record format for the store.
38868 * @param {Object} value the value to set as. or false on reset?
38870 setFromData : function(o){
38877 var dv = ''; // display value
38878 var vv = ''; // value value..
38880 if (this.displayField) {
38881 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
38883 // this is an error condition!!!
38884 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
38887 if(this.valueField){
38888 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
38891 var close = this.closeTriggerEl();
38894 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
38897 if(this.hiddenField){
38898 this.hiddenField.dom.value = vv;
38900 this.lastSelectionText = dv;
38901 Roo.bootstrap.PhoneInput.superclass.setValue.call(this, dv);
38905 // no hidden field.. - we store the value in 'value', but still display
38906 // display field!!!!
38907 this.lastSelectionText = dv;
38908 Roo.bootstrap.PhoneInput.superclass.setValue.call(this, dv);
38915 reset : function(){
38916 // overridden so that last data is reset..
38923 this.setValue(this.originalValue);
38924 //this.clearInvalid();
38925 this.lastData = false;
38927 this.view.clearSelections();
38933 findRecord : function(prop, value){
38935 if(this.store.getCount() > 0){
38936 this.store.each(function(r){
38937 if(r.data[prop] == value){
38947 getName: function()
38949 // returns hidden if it's set..
38950 if (!this.rendered) {return ''};
38951 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
38955 onViewMove : function(e, t){
38956 this.inKeyMode = false;
38960 onViewOver : function(e, t){
38961 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
38964 var item = this.view.findItemFromChild(t);
38967 var index = this.view.indexOf(item);
38968 this.select(index, false);
38973 onViewClick : function(view, doFocus, el, e)
38975 var index = this.view.getSelectedIndexes()[0];
38977 var r = this.store.getAt(index);
38981 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
38988 Roo.each(this.tickItems, function(v,k){
38990 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
38992 _this.tickItems.splice(k, 1);
38994 if(typeof(e) == 'undefined' && view == false){
38995 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
39007 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
39008 this.tickItems.push(r.data);
39011 if(typeof(e) == 'undefined' && view == false){
39012 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
39019 this.onSelect(r, index);
39021 if(doFocus !== false && !this.blockFocus){
39022 this.inputEl().focus();
39027 restrictHeight : function(){
39028 //this.innerList.dom.style.height = '';
39029 //var inner = this.innerList.dom;
39030 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39031 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39032 //this.list.beginUpdate();
39033 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39034 this.list.alignTo(this.inputEl(), this.listAlign);
39035 this.list.alignTo(this.inputEl(), this.listAlign);
39036 //this.list.endUpdate();
39040 onEmptyResults : function(){
39042 if(this.tickable && this.editable){
39043 this.restrictHeight();
39051 * Returns true if the dropdown list is expanded, else false.
39053 isExpanded : function(){
39054 return this.list.isVisible();
39058 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39059 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39060 * @param {String} value The data value of the item to select
39061 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39062 * selected item if it is not currently in view (defaults to true)
39063 * @return {Boolean} True if the value matched an item in the list, else false
39065 selectByValue : function(v, scrollIntoView){
39066 if(v !== undefined && v !== null){
39067 var r = this.findRecord(this.valueField || this.displayField, v);
39069 this.select(this.store.indexOf(r), scrollIntoView);
39077 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39078 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39079 * @param {Number} index The zero-based index of the list item to select
39080 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39081 * selected item if it is not currently in view (defaults to true)
39083 select : function(index, scrollIntoView){
39084 this.selectedIndex = index;
39085 this.view.select(index);
39086 if(scrollIntoView !== false){
39087 var el = this.view.getNode(index);
39089 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
39092 this.list.scrollChildIntoView(el, false);
39098 selectNext : function(){
39099 var ct = this.store.getCount();
39101 if(this.selectedIndex == -1){
39103 }else if(this.selectedIndex < ct-1){
39104 this.select(this.selectedIndex+1);
39110 selectPrev : function(){
39111 var ct = this.store.getCount();
39113 if(this.selectedIndex == -1){
39115 }else if(this.selectedIndex != 0){
39116 this.select(this.selectedIndex-1);
39122 onKeyUp : function(e){
39123 if(this.editable !== false && !e.isSpecialKey()){
39124 this.lastKey = e.getKey();
39125 this.dqTask.delay(this.queryDelay);
39130 validateBlur : function(){
39131 return !this.list || !this.list.isVisible();
39135 initQuery : function(){
39137 var v = this.getRawValue();
39139 if(this.tickable && this.editable){
39140 v = this.tickableInputEl().getValue();
39147 doForce : function(){
39148 if(this.inputEl().dom.value.length > 0){
39149 this.inputEl().dom.value =
39150 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39156 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39157 * query allowing the query action to be canceled if needed.
39158 * @param {String} query The SQL query to execute
39159 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39160 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39161 * saved in the current store (defaults to false)
39163 doQuery : function(q, forceAll){
39165 if(q === undefined || q === null){
39170 forceAll: forceAll,
39174 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39179 forceAll = qe.forceAll;
39180 if(forceAll === true || (q.length >= this.minChars)){
39182 this.hasQuery = true;
39184 if(this.lastQuery != q || this.alwaysQuery){
39185 this.lastQuery = q;
39186 if(this.mode == 'local'){
39187 this.selectedIndex = -1;
39189 this.store.clearFilter();
39192 if(this.specialFilter){
39193 this.fireEvent('specialfilter', this);
39198 this.store.filter(this.displayField, q);
39201 this.store.fireEvent("datachanged", this.store);
39208 this.store.baseParams[this.queryParam] = q;
39210 var options = {params : this.getParams(q)};
39213 options.add = true;
39214 options.params.start = this.page * this.pageSize;
39217 this.store.load(options);
39220 * this code will make the page width larger, at the beginning, the list not align correctly,
39221 * we should expand the list on onLoad
39222 * so command out it
39227 this.selectedIndex = -1;
39232 this.loadNext = false;
39236 getParams : function(q){
39238 //p[this.queryParam] = q;
39242 p.limit = this.pageSize;
39248 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39250 collapse : function(){
39251 if(!this.isExpanded()){
39257 this.hasFocus = false;
39261 this.cancelBtn.hide();
39262 this.trigger.show();
39265 this.tickableInputEl().dom.value = '';
39266 this.tickableInputEl().blur();
39271 Roo.get(document).un('mousedown', this.collapseIf, this);
39272 Roo.get(document).un('mousewheel', this.collapseIf, this);
39273 if (!this.editable) {
39274 Roo.get(document).un('keydown', this.listKeyPress, this);
39276 this.fireEvent('collapse', this);
39282 collapseIf : function(e){
39283 var in_combo = e.within(this.el);
39284 var in_list = e.within(this.list);
39285 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39287 if (in_combo || in_list || is_list) {
39288 //e.stopPropagation();
39293 this.onTickableFooterButtonClick(e, false, false);
39301 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39303 expand : function(){
39305 if(this.isExpanded() || !this.hasFocus){
39309 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39310 this.list.setWidth(lw);
39316 this.restrictHeight();
39320 this.tickItems = Roo.apply([], this.item);
39323 this.cancelBtn.show();
39324 this.trigger.hide();
39327 this.tickableInputEl().focus();
39332 Roo.get(document).on('mousedown', this.collapseIf, this);
39333 Roo.get(document).on('mousewheel', this.collapseIf, this);
39334 if (!this.editable) {
39335 Roo.get(document).on('keydown', this.listKeyPress, this);
39338 this.fireEvent('expand', this);
39342 // Implements the default empty TriggerField.onTriggerClick function
39343 onTriggerClick : function(e)
39345 Roo.log('trigger click');
39347 if(this.disabled || !this.triggerList){
39352 this.loadNext = false;
39354 if(this.isExpanded()){
39356 if (!this.blockFocus) {
39357 this.inputEl().focus();
39361 this.hasFocus = true;
39362 if(this.triggerAction == 'all') {
39363 this.doQuery(this.allQuery, true);
39365 this.doQuery(this.getRawValue());
39367 if (!this.blockFocus) {
39368 this.inputEl().focus();
39373 onTickableTriggerClick : function(e)
39380 this.loadNext = false;
39381 this.hasFocus = true;
39383 if(this.triggerAction == 'all') {
39384 this.doQuery(this.allQuery, true);
39386 this.doQuery(this.getRawValue());
39390 onSearchFieldClick : function(e)
39392 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
39393 this.onTickableFooterButtonClick(e, false, false);
39397 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
39402 this.loadNext = false;
39403 this.hasFocus = true;
39405 if(this.triggerAction == 'all') {
39406 this.doQuery(this.allQuery, true);
39408 this.doQuery(this.getRawValue());
39412 listKeyPress : function(e)
39414 //Roo.log('listkeypress');
39415 // scroll to first matching element based on key pres..
39416 if (e.isSpecialKey()) {
39419 var k = String.fromCharCode(e.getKey()).toUpperCase();
39422 var csel = this.view.getSelectedNodes();
39423 var cselitem = false;
39425 var ix = this.view.indexOf(csel[0]);
39426 cselitem = this.store.getAt(ix);
39427 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
39433 this.store.each(function(v) {
39435 // start at existing selection.
39436 if (cselitem.id == v.id) {
39442 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
39443 match = this.store.indexOf(v);
39449 if (match === false) {
39450 return true; // no more action?
39453 this.view.select(match);
39454 var sn = Roo.get(this.view.getSelectedNodes()[0]);
39455 sn.scrollIntoView(sn.dom.parentNode, false);
39458 onViewScroll : function(e, t){
39460 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){
39464 this.hasQuery = true;
39466 this.loading = this.list.select('.loading', true).first();
39468 if(this.loading === null){
39469 this.list.createChild({
39471 cls: 'loading roo-select2-more-results roo-select2-active',
39472 html: 'Loading more results...'
39475 this.loading = this.list.select('.loading', true).first();
39477 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
39479 this.loading.hide();
39482 this.loading.show();
39487 this.loadNext = true;
39489 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
39494 addItem : function(o)
39496 var dv = ''; // display value
39498 if (this.displayField) {
39499 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39501 // this is an error condition!!!
39502 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39509 var choice = this.choices.createChild({
39511 cls: 'roo-select2-search-choice',
39520 cls: 'roo-select2-search-choice-close fa fa-times',
39525 }, this.searchField);
39527 var close = choice.select('a.roo-select2-search-choice-close', true).first();
39529 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
39537 this.inputEl().dom.value = '';
39542 onRemoveItem : function(e, _self, o)
39544 e.preventDefault();
39546 this.lastItem = Roo.apply([], this.item);
39548 var index = this.item.indexOf(o.data) * 1;
39551 Roo.log('not this item?!');
39555 this.item.splice(index, 1);
39560 this.fireEvent('remove', this, e);
39566 syncValue : function()
39568 if(!this.item.length){
39575 Roo.each(this.item, function(i){
39576 if(_this.valueField){
39577 value.push(i[_this.valueField]);
39584 this.value = value.join(',');
39586 if(this.hiddenField){
39587 this.hiddenField.dom.value = this.value;
39590 this.store.fireEvent("datachanged", this.store);
39595 clearItem : function()
39597 if(!this.multiple){
39603 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
39611 if(this.tickable && !Roo.isTouch){
39612 this.view.refresh();
39616 inputEl: function ()
39618 if(Roo.isIOS && this.useNativeIOS){
39619 return this.el.select('select.roo-ios-select', true).first();
39622 if(Roo.isTouch && this.mobileTouchView){
39623 return this.el.select('input.form-control',true).first();
39627 return this.searchField;
39630 return this.el.select('input.form-control',true).first();
39633 onTickableFooterButtonClick : function(e, btn, el)
39635 e.preventDefault();
39637 this.lastItem = Roo.apply([], this.item);
39639 if(btn && btn.name == 'cancel'){
39640 this.tickItems = Roo.apply([], this.item);
39649 Roo.each(this.tickItems, function(o){
39657 validate : function()
39659 var v = this.getRawValue();
39662 v = this.getValue();
39665 if(this.disabled || this.allowBlank || v.length){
39670 this.markInvalid();
39674 tickableInputEl : function()
39676 if(!this.tickable || !this.editable){
39677 return this.inputEl();
39680 return this.inputEl().select('.roo-select2-search-field-input', true).first();
39684 getAutoCreateTouchView : function()
39689 cls: 'form-group' //input-group
39695 type : this.inputType,
39696 cls : 'form-control x-combo-noedit',
39697 autocomplete: 'new-password',
39698 placeholder : this.placeholder || '',
39703 input.name = this.name;
39707 input.cls += ' input-' + this.size;
39710 if (this.disabled) {
39711 input.disabled = true;
39722 inputblock.cls += ' input-group';
39724 inputblock.cn.unshift({
39726 cls : 'input-group-addon',
39731 if(this.removable && !this.multiple){
39732 inputblock.cls += ' roo-removable';
39734 inputblock.cn.push({
39737 cls : 'roo-combo-removable-btn close'
39741 if(this.hasFeedback && !this.allowBlank){
39743 inputblock.cls += ' has-feedback';
39745 inputblock.cn.push({
39747 cls: 'glyphicon form-control-feedback'
39754 inputblock.cls += (this.before) ? '' : ' input-group';
39756 inputblock.cn.push({
39758 cls : 'input-group-addon',
39769 cls: 'form-hidden-field'
39783 cls: 'form-hidden-field'
39787 cls: 'roo-select2-choices',
39791 cls: 'roo-select2-search-field',
39804 cls: 'roo-select2-container input-group roo-touchview-PhoneInput ',
39810 if(!this.multiple && this.showToggleBtn){
39817 if (this.caret != false) {
39820 cls: 'fa fa-' + this.caret
39825 PhoneInput.cn.push({
39827 cls : 'input-group-addon btn dropdown-toggle',
39832 cls: 'PhoneInput-clear',
39846 PhoneInput.cls += ' roo-select2-container-multi';
39849 var align = this.labelAlign || this.parentLabelAlign();
39851 if (align ==='left' && this.fieldLabel.length) {
39856 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
39857 tooltip : 'This field is required'
39861 cls : 'control-label',
39862 html : this.fieldLabel
39873 var labelCfg = cfg.cn[1];
39874 var contentCfg = cfg.cn[2];
39877 if(this.indicatorpos == 'right'){
39881 cls : 'control-label',
39882 html : this.fieldLabel,
39886 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
39887 tooltip : 'This field is required'
39900 labelCfg = cfg.cn[0];
39901 contentCfg = cfg.cn[2];
39903 if(this.labelWidth > 12){
39904 labelCfg.style = "width: " + this.labelWidth + 'px';
39907 if(this.labelWidth < 13 && this.labelmd == 0){
39908 this.labelmd = this.labelWidth;
39911 if(this.labellg > 0){
39912 labelCfg.cls += ' col-lg-' + this.labellg;
39913 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
39916 if(this.labelmd > 0){
39917 labelCfg.cls += ' col-md-' + this.labelmd;
39918 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
39921 if(this.labelsm > 0){
39922 labelCfg.cls += ' col-sm-' + this.labelsm;
39923 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
39926 if(this.labelxs > 0){
39927 labelCfg.cls += ' col-xs-' + this.labelxs;
39928 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
39932 } else if ( this.fieldLabel.length) {
39936 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
39937 tooltip : 'This field is required'
39941 cls : 'control-label',
39942 html : this.fieldLabel
39953 if(this.indicatorpos == 'right'){
39957 cls : 'control-label',
39958 html : this.fieldLabel,
39962 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
39963 tooltip : 'This field is required'
39976 cfg.cn = PhoneInput;
39980 var settings = this;
39982 ['xs','sm','md','lg'].map(function(size){
39983 if (settings[size]) {
39984 cfg.cls += ' col-' + size + '-' + settings[size];
39991 initTouchView : function()
39993 this.renderTouchView();
39995 this.touchViewEl.on('scroll', function(){
39996 this.el.dom.scrollTop = 0;
39999 this.originalValue = this.getValue();
40001 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
40003 this.inputEl().on("click", this.showTouchView, this);
40004 if (this.triggerEl) {
40005 this.triggerEl.on("click", this.showTouchView, this);
40009 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
40010 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
40012 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
40014 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
40015 this.store.on('load', this.onTouchViewLoad, this);
40016 this.store.on('loadexception', this.onTouchViewLoadException, this);
40018 if(this.hiddenName){
40020 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
40022 this.hiddenField.dom.value =
40023 this.hiddenValue !== undefined ? this.hiddenValue :
40024 this.value !== undefined ? this.value : '';
40026 this.el.dom.removeAttribute('name');
40027 this.hiddenField.dom.setAttribute('name', this.hiddenName);
40031 this.choices = this.el.select('ul.roo-select2-choices', true).first();
40032 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
40035 if(this.removable && !this.multiple){
40036 var close = this.closeTriggerEl();
40038 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
40039 close.on('click', this.removeBtnClick, this, close);
40043 * fix the bug in Safari iOS8
40045 this.inputEl().on("focus", function(e){
40046 document.activeElement.blur();
40054 renderTouchView : function()
40056 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.PhoneInput.touchViewTemplate);
40057 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40059 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
40060 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40062 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
40063 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40064 this.touchViewBodyEl.setStyle('overflow', 'auto');
40066 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
40067 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40069 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
40070 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40074 showTouchView : function()
40080 this.touchViewHeaderEl.hide();
40082 if(this.modalTitle.length){
40083 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
40084 this.touchViewHeaderEl.show();
40087 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
40088 this.touchViewEl.show();
40090 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
40091 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
40092 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
40094 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
40096 if(this.modalTitle.length){
40097 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
40100 this.touchViewBodyEl.setHeight(bodyHeight);
40104 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
40106 this.touchViewEl.addClass('in');
40109 this.doTouchViewQuery();
40113 hideTouchView : function()
40115 this.touchViewEl.removeClass('in');
40119 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
40121 this.touchViewEl.setStyle('display', 'none');
40126 setTouchViewValue : function()
40133 Roo.each(this.tickItems, function(o){
40138 this.hideTouchView();
40141 doTouchViewQuery : function()
40150 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
40154 if(!this.alwaysQuery || this.mode == 'local'){
40155 this.onTouchViewLoad();
40162 onTouchViewBeforeLoad : function(combo,opts)
40168 onTouchViewLoad : function()
40170 if(this.store.getCount() < 1){
40171 this.onTouchViewEmptyResults();
40175 this.clearTouchView();
40177 var rawValue = this.getRawValue();
40179 var template = (this.multiple) ? Roo.bootstrap.PhoneInput.listItemCheckbox : Roo.bootstrap.PhoneInput.listItemRadio;
40181 this.tickItems = [];
40183 this.store.data.each(function(d, rowIndex){
40184 var row = this.touchViewListGroup.createChild(template);
40186 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
40187 row.addClass(d.data.cls);
40190 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
40193 html : d.data[this.displayField]
40196 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
40197 row.select('.roo-PhoneInput-list-group-item-value', true).first().dom.innerHTML = cfg.html;
40200 row.removeClass('selected');
40201 if(!this.multiple && this.valueField &&
40202 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
40205 row.select('.roo-PhoneInput-list-group-item-box > input', true).first().attr('checked', true);
40206 row.addClass('selected');
40209 if(this.multiple && this.valueField &&
40210 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
40214 row.select('.roo-PhoneInput-list-group-item-box > input', true).first().attr('checked', true);
40215 this.tickItems.push(d.data);
40218 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
40222 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-PhoneInput-list-group-item-box > input:checked', true).first();
40224 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
40226 if(this.modalTitle.length){
40227 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
40230 var listHeight = this.touchViewListGroup.getHeight();
40234 if(firstChecked && listHeight > bodyHeight){
40235 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
40240 onTouchViewLoadException : function()
40242 this.hideTouchView();
40245 onTouchViewEmptyResults : function()
40247 this.clearTouchView();
40249 this.touchViewListGroup.createChild(Roo.bootstrap.PhoneInput.emptyResult);
40251 this.touchViewListGroup.select('.roo-PhoneInput-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
40255 clearTouchView : function()
40257 this.touchViewListGroup.dom.innerHTML = '';
40260 onTouchViewClick : function(e, el, o)
40262 e.preventDefault();
40265 var rowIndex = o.rowIndex;
40267 var r = this.store.getAt(rowIndex);
40269 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
40271 if(!this.multiple){
40272 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-PhoneInput-list-group-item-box > input:checked', true).elements, function(c){
40273 c.dom.removeAttribute('checked');
40276 row.select('.roo-PhoneInput-list-group-item-box > input', true).first().attr('checked', true);
40278 this.setFromData(r.data);
40280 var close = this.closeTriggerEl();
40286 this.hideTouchView();
40288 this.fireEvent('select', this, r, rowIndex);
40293 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
40294 row.select('.roo-PhoneInput-list-group-item-box > input', true).first().dom.removeAttribute('checked');
40295 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
40299 row.select('.roo-PhoneInput-list-group-item-box > input', true).first().attr('checked', true);
40300 this.addItem(r.data);
40301 this.tickItems.push(r.data);
40305 getAutoCreateNativeIOS : function()
40308 cls: 'form-group' //input-group,
40313 cls : 'roo-ios-select'
40317 PhoneInput.name = this.name;
40320 if (this.disabled) {
40321 PhoneInput.disabled = true;
40324 var settings = this;
40326 ['xs','sm','md','lg'].map(function(size){
40327 if (settings[size]) {
40328 cfg.cls += ' col-' + size + '-' + settings[size];
40332 cfg.cn = PhoneInput;
40338 initIOSView : function()
40340 this.store.on('load', this.onIOSViewLoad, this);
40345 onIOSViewLoad : function()
40347 if(this.store.getCount() < 1){
40351 this.clearIOSView();
40353 if(this.allowBlank) {
40355 var default_text = '-- SELECT --';
40357 var opt = this.inputEl().createChild({
40360 html : default_text
40364 o[this.valueField] = 0;
40365 o[this.displayField] = default_text;
40367 this.ios_options.push({
40374 this.store.data.each(function(d, rowIndex){
40378 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
40379 html = d.data[this.displayField];
40384 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
40385 value = d.data[this.valueField];
40394 if(this.value == d.data[this.valueField]){
40395 option['selected'] = true;
40398 var opt = this.inputEl().createChild(option);
40400 this.ios_options.push({
40407 this.inputEl().on('change', function(){
40408 this.fireEvent('select', this);
40413 clearIOSView: function()
40415 this.inputEl().dom.innerHTML = '';
40417 this.ios_options = [];
40420 setIOSValue: function(v)
40424 if(!this.ios_options){
40428 Roo.each(this.ios_options, function(opts){
40430 opts.el.dom.removeAttribute('selected');
40432 if(opts.data[this.valueField] != v){
40436 opts.el.dom.setAttribute('selected', true);
40442 * @cfg {Boolean} grow
40446 * @cfg {Number} growMin
40450 * @cfg {Number} growMax
40459 Roo.apply(Roo.bootstrap.PhoneInput, {
40463 cls: 'modal-header',
40485 cls: 'list-group-item',
40489 cls: 'roo-PhoneInput-list-group-item-value'
40493 cls: 'roo-PhoneInput-list-group-item-box pull-xs-right radio-inline radio radio-info',
40507 listItemCheckbox : {
40509 cls: 'list-group-item',
40513 cls: 'roo-PhoneInput-list-group-item-value'
40517 cls: 'roo-PhoneInput-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
40533 cls: 'alert alert-danger roo-PhoneInput-touch-view-empty-result'
40538 cls: 'modal-footer',
40546 cls: 'col-xs-6 text-left',
40549 cls: 'btn btn-danger roo-touch-view-cancel',
40555 cls: 'col-xs-6 text-right',
40558 cls: 'btn btn-success roo-touch-view-ok',