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 (function() { _this.hide(); }).defer(100);
2129 onMouseOver : function(e){
2130 var t = this.findTargetItem(e);
2133 // if(t.canActivate && !t.disabled){
2134 // this.setActiveItem(t, true);
2138 this.fireEvent("mouseover", this, e, t);
2140 isVisible : function(){
2141 return !this.hidden;
2143 onMouseOut : function(e){
2144 var t = this.findTargetItem(e);
2147 // if(t == this.activeItem && t.shouldDeactivate(e)){
2148 // this.activeItem.deactivate();
2149 // delete this.activeItem;
2152 this.fireEvent("mouseout", this, e, t);
2157 * Displays this menu relative to another element
2158 * @param {String/HTMLElement/Roo.Element} element The element to align to
2159 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2160 * the element (defaults to this.defaultAlign)
2161 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2163 show : function(el, pos, parentMenu){
2164 this.parentMenu = parentMenu;
2168 this.fireEvent("beforeshow", this);
2169 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2172 * Displays this menu at a specific xy position
2173 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2174 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2176 showAt : function(xy, parentMenu, /* private: */_e){
2177 this.parentMenu = parentMenu;
2182 this.fireEvent("beforeshow", this);
2183 //xy = this.el.adjustForConstraints(xy);
2187 this.hideMenuItems();
2188 this.hidden = false;
2189 this.triggerEl.addClass('open');
2191 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2192 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2195 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2200 this.fireEvent("show", this);
2206 this.doFocus.defer(50, this);
2210 doFocus : function(){
2212 this.focusEl.focus();
2217 * Hides this menu and optionally all parent menus
2218 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2220 hide : function(deep)
2223 this.hideMenuItems();
2224 if(this.el && this.isVisible()){
2225 this.fireEvent("beforehide", this);
2226 if(this.activeItem){
2227 this.activeItem.deactivate();
2228 this.activeItem = null;
2230 this.triggerEl.removeClass('open');;
2232 this.fireEvent("hide", this);
2234 if(deep === true && this.parentMenu){
2235 this.parentMenu.hide(true);
2239 onTriggerClick : function(e)
2241 Roo.log('trigger click');
2243 var target = e.getTarget();
2245 Roo.log(target.nodeName.toLowerCase());
2247 if(target.nodeName.toLowerCase() === 'i'){
2253 onTriggerPress : function(e)
2255 Roo.log('trigger press');
2256 //Roo.log(e.getTarget());
2257 // Roo.log(this.triggerEl.dom);
2259 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2260 var pel = Roo.get(e.getTarget());
2261 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2262 Roo.log('is treeview or dropdown?');
2266 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2270 if (this.isVisible()) {
2275 this.show(this.triggerEl, false, false);
2278 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2285 hideMenuItems : function()
2287 Roo.log("hide Menu Items");
2291 //$(backdrop).remove()
2292 this.el.select('.open',true).each(function(aa) {
2294 aa.removeClass('open');
2295 //var parent = getParent($(this))
2296 //var relatedTarget = { relatedTarget: this }
2298 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2299 //if (e.isDefaultPrevented()) return
2300 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2303 addxtypeChild : function (tree, cntr) {
2304 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2306 this.menuitems.add(comp);
2327 * @class Roo.bootstrap.MenuItem
2328 * @extends Roo.bootstrap.Component
2329 * Bootstrap MenuItem class
2330 * @cfg {String} html the menu label
2331 * @cfg {String} href the link
2332 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2333 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2334 * @cfg {Boolean} active used on sidebars to highlight active itesm
2335 * @cfg {String} fa favicon to show on left of menu item.
2336 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2340 * Create a new MenuItem
2341 * @param {Object} config The config object
2345 Roo.bootstrap.MenuItem = function(config){
2346 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2351 * The raw click event for the entire grid.
2352 * @param {Roo.bootstrap.MenuItem} this
2353 * @param {Roo.EventObject} e
2359 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2363 preventDefault: false,
2364 isContainer : false,
2368 getAutoCreate : function(){
2370 if(this.isContainer){
2373 cls: 'dropdown-menu-item'
2387 if (this.fa !== false) {
2390 cls : 'fa fa-' + this.fa
2399 cls: 'dropdown-menu-item',
2402 if (this.parent().type == 'treeview') {
2403 cfg.cls = 'treeview-menu';
2406 cfg.cls += ' active';
2411 anc.href = this.href || cfg.cn[0].href ;
2412 ctag.html = this.html || cfg.cn[0].html ;
2416 initEvents: function()
2418 if (this.parent().type == 'treeview') {
2419 this.el.select('a').on('click', this.onClick, this);
2422 this.menu.parentType = this.xtype;
2423 this.menu.triggerEl = this.el;
2424 this.menu = this.addxtype(Roo.apply({}, this.menu));
2428 onClick : function(e)
2430 Roo.log('item on click ');
2432 if(this.preventDefault){
2435 //this.parent().hideMenuItems();
2437 this.fireEvent('click', this, e);
2456 * @class Roo.bootstrap.MenuSeparator
2457 * @extends Roo.bootstrap.Component
2458 * Bootstrap MenuSeparator class
2461 * Create a new MenuItem
2462 * @param {Object} config The config object
2466 Roo.bootstrap.MenuSeparator = function(config){
2467 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2470 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2472 getAutoCreate : function(){
2491 * @class Roo.bootstrap.Modal
2492 * @extends Roo.bootstrap.Component
2493 * Bootstrap Modal class
2494 * @cfg {String} title Title of dialog
2495 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2496 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2497 * @cfg {Boolean} specificTitle default false
2498 * @cfg {Array} buttons Array of buttons or standard button set..
2499 * @cfg {String} buttonPosition (left|right|center) default right
2500 * @cfg {Boolean} animate default true
2501 * @cfg {Boolean} allow_close default true
2502 * @cfg {Boolean} fitwindow default false
2503 * @cfg {String} size (sm|lg) default empty
2507 * Create a new Modal Dialog
2508 * @param {Object} config The config object
2511 Roo.bootstrap.Modal = function(config){
2512 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2517 * The raw btnclick event for the button
2518 * @param {Roo.EventObject} e
2523 * Fire when dialog resize
2524 * @param {Roo.bootstrap.Modal} this
2525 * @param {Roo.EventObject} e
2529 this.buttons = this.buttons || [];
2532 this.tmpl = Roo.factory(this.tmpl);
2537 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2539 title : 'test dialog',
2549 specificTitle: false,
2551 buttonPosition: 'right',
2570 onRender : function(ct, position)
2572 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2575 var cfg = Roo.apply({}, this.getAutoCreate());
2578 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2580 //if (!cfg.name.length) {
2584 cfg.cls += ' ' + this.cls;
2587 cfg.style = this.style;
2589 this.el = Roo.get(document.body).createChild(cfg, position);
2591 //var type = this.el.dom.type;
2594 if(this.tabIndex !== undefined){
2595 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2598 this.dialogEl = this.el.select('.modal-dialog',true).first();
2599 this.bodyEl = this.el.select('.modal-body',true).first();
2600 this.closeEl = this.el.select('.modal-header .close', true).first();
2601 this.headerEl = this.el.select('.modal-header',true).first();
2602 this.titleEl = this.el.select('.modal-title',true).first();
2603 this.footerEl = this.el.select('.modal-footer',true).first();
2605 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2606 this.maskEl.enableDisplayMode("block");
2608 //this.el.addClass("x-dlg-modal");
2610 if (this.buttons.length) {
2611 Roo.each(this.buttons, function(bb) {
2612 var b = Roo.apply({}, bb);
2613 b.xns = b.xns || Roo.bootstrap;
2614 b.xtype = b.xtype || 'Button';
2615 if (typeof(b.listeners) == 'undefined') {
2616 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2619 var btn = Roo.factory(b);
2621 btn.render(this.el.select('.modal-footer div').first());
2625 // render the children.
2628 if(typeof(this.items) != 'undefined'){
2629 var items = this.items;
2632 for(var i =0;i < items.length;i++) {
2633 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2637 this.items = nitems;
2639 // where are these used - they used to be body/close/footer
2643 //this.el.addClass([this.fieldClass, this.cls]);
2647 getAutoCreate : function(){
2652 html : this.html || ''
2657 cls : 'modal-title',
2661 if(this.specificTitle){
2667 if (this.allow_close) {
2679 if(this.size.length){
2680 size = 'modal-' + this.size;
2685 style : 'display: none',
2688 cls: "modal-dialog " + size,
2691 cls : "modal-content",
2694 cls : 'modal-header',
2699 cls : 'modal-footer',
2703 cls: 'btn-' + this.buttonPosition
2720 modal.cls += ' fade';
2726 getChildContainer : function() {
2731 getButtonContainer : function() {
2732 return this.el.select('.modal-footer div',true).first();
2735 initEvents : function()
2737 if (this.allow_close) {
2738 this.closeEl.on('click', this.hide, this);
2740 Roo.EventManager.onWindowResize(this.resize, this, true);
2747 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2748 if (this.fitwindow) {
2749 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2750 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2755 setSize : function(w,h)
2765 if (!this.rendered) {
2769 this.el.setStyle('display', 'block');
2771 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2774 this.el.addClass('in');
2777 this.el.addClass('in');
2781 // not sure how we can show data in here..
2783 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2786 Roo.get(document.body).addClass("x-body-masked");
2788 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2789 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2794 this.fireEvent('show', this);
2796 // set zindex here - otherwise it appears to be ignored...
2797 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2800 this.items.forEach( function(e) {
2801 e.layout ? e.layout() : false;
2809 if(this.fireEvent("beforehide", this) !== false){
2811 Roo.get(document.body).removeClass("x-body-masked");
2812 this.el.removeClass('in');
2813 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2815 if(this.animate){ // why
2817 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2819 this.el.setStyle('display', 'none');
2821 this.fireEvent('hide', this);
2825 addButton : function(str, cb)
2829 var b = Roo.apply({}, { html : str } );
2830 b.xns = b.xns || Roo.bootstrap;
2831 b.xtype = b.xtype || 'Button';
2832 if (typeof(b.listeners) == 'undefined') {
2833 b.listeners = { click : cb.createDelegate(this) };
2836 var btn = Roo.factory(b);
2838 btn.render(this.el.select('.modal-footer div').first());
2844 setDefaultButton : function(btn)
2846 //this.el.select('.modal-footer').()
2850 resizeTo: function(w,h)
2854 this.dialogEl.setWidth(w);
2855 if (this.diff === false) {
2856 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2859 this.bodyEl.setHeight(h-this.diff);
2861 this.fireEvent('resize', this);
2864 setContentSize : function(w, h)
2868 onButtonClick: function(btn,e)
2871 this.fireEvent('btnclick', btn.name, e);
2874 * Set the title of the Dialog
2875 * @param {String} str new Title
2877 setTitle: function(str) {
2878 this.titleEl.dom.innerHTML = str;
2881 * Set the body of the Dialog
2882 * @param {String} str new Title
2884 setBody: function(str) {
2885 this.bodyEl.dom.innerHTML = str;
2888 * Set the body of the Dialog using the template
2889 * @param {Obj} data - apply this data to the template and replace the body contents.
2891 applyBody: function(obj)
2894 Roo.log("Error - using apply Body without a template");
2897 this.tmpl.overwrite(this.bodyEl, obj);
2903 Roo.apply(Roo.bootstrap.Modal, {
2905 * Button config that displays a single OK button
2914 * Button config that displays Yes and No buttons
2930 * Button config that displays OK and Cancel buttons
2945 * Button config that displays Yes, No and Cancel buttons
2969 * messagebox - can be used as a replace
2973 * @class Roo.MessageBox
2974 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2978 Roo.Msg.alert('Status', 'Changes saved successfully.');
2980 // Prompt for user data:
2981 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2983 // process text value...
2987 // Show a dialog using config options:
2989 title:'Save Changes?',
2990 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2991 buttons: Roo.Msg.YESNOCANCEL,
2998 Roo.bootstrap.MessageBox = function(){
2999 var dlg, opt, mask, waitTimer;
3000 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3001 var buttons, activeTextEl, bwidth;
3005 var handleButton = function(button){
3007 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3011 var handleHide = function(){
3013 dlg.el.removeClass(opt.cls);
3016 // Roo.TaskMgr.stop(waitTimer);
3017 // waitTimer = null;
3022 var updateButtons = function(b){
3025 buttons["ok"].hide();
3026 buttons["cancel"].hide();
3027 buttons["yes"].hide();
3028 buttons["no"].hide();
3029 //dlg.footer.dom.style.display = 'none';
3032 dlg.footerEl.dom.style.display = '';
3033 for(var k in buttons){
3034 if(typeof buttons[k] != "function"){
3037 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3038 width += buttons[k].el.getWidth()+15;
3048 var handleEsc = function(d, k, e){
3049 if(opt && opt.closable !== false){
3059 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3060 * @return {Roo.BasicDialog} The BasicDialog element
3062 getDialog : function(){
3064 dlg = new Roo.bootstrap.Modal( {
3067 //constraintoviewport:false,
3069 //collapsible : false,
3074 //buttonAlign:"center",
3075 closeClick : function(){
3076 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3079 handleButton("cancel");
3084 dlg.on("hide", handleHide);
3086 //dlg.addKeyListener(27, handleEsc);
3088 this.buttons = buttons;
3089 var bt = this.buttonText;
3090 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3091 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3092 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3093 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3095 bodyEl = dlg.bodyEl.createChild({
3097 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3098 '<textarea class="roo-mb-textarea"></textarea>' +
3099 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3101 msgEl = bodyEl.dom.firstChild;
3102 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3103 textboxEl.enableDisplayMode();
3104 textboxEl.addKeyListener([10,13], function(){
3105 if(dlg.isVisible() && opt && opt.buttons){
3108 }else if(opt.buttons.yes){
3109 handleButton("yes");
3113 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3114 textareaEl.enableDisplayMode();
3115 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3116 progressEl.enableDisplayMode();
3118 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3119 //var pf = progressEl.dom.firstChild;
3121 //pp = Roo.get(pf.firstChild);
3122 //pp.setHeight(pf.offsetHeight);
3130 * Updates the message box body text
3131 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3132 * the XHTML-compliant non-breaking space character '&#160;')
3133 * @return {Roo.MessageBox} This message box
3135 updateText : function(text)
3137 if(!dlg.isVisible() && !opt.width){
3138 dlg.dialogEl.setWidth(this.maxWidth);
3139 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3141 msgEl.innerHTML = text || ' ';
3143 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3144 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3146 Math.min(opt.width || cw , this.maxWidth),
3147 Math.max(opt.minWidth || this.minWidth, bwidth)
3150 activeTextEl.setWidth(w);
3152 if(dlg.isVisible()){
3153 dlg.fixedcenter = false;
3155 // to big, make it scroll. = But as usual stupid IE does not support
3158 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3159 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3160 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3162 bodyEl.dom.style.height = '';
3163 bodyEl.dom.style.overflowY = '';
3166 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3168 bodyEl.dom.style.overflowX = '';
3171 dlg.setContentSize(w, bodyEl.getHeight());
3172 if(dlg.isVisible()){
3173 dlg.fixedcenter = true;
3179 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3180 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3181 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3182 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3183 * @return {Roo.MessageBox} This message box
3185 updateProgress : function(value, text){
3187 this.updateText(text);
3189 if (pp) { // weird bug on my firefox - for some reason this is not defined
3190 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3196 * Returns true if the message box is currently displayed
3197 * @return {Boolean} True if the message box is visible, else false
3199 isVisible : function(){
3200 return dlg && dlg.isVisible();
3204 * Hides the message box if it is displayed
3207 if(this.isVisible()){
3213 * Displays a new message box, or reinitializes an existing message box, based on the config options
3214 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3215 * The following config object properties are supported:
3217 Property Type Description
3218 ---------- --------------- ------------------------------------------------------------------------------------
3219 animEl String/Element An id or Element from which the message box should animate as it opens and
3220 closes (defaults to undefined)
3221 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3222 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3223 closable Boolean False to hide the top-right close button (defaults to true). Note that
3224 progress and wait dialogs will ignore this property and always hide the
3225 close button as they can only be closed programmatically.
3226 cls String A custom CSS class to apply to the message box element
3227 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3228 displayed (defaults to 75)
3229 fn Function A callback function to execute after closing the dialog. The arguments to the
3230 function will be btn (the name of the button that was clicked, if applicable,
3231 e.g. "ok"), and text (the value of the active text field, if applicable).
3232 Progress and wait dialogs will ignore this option since they do not respond to
3233 user actions and can only be closed programmatically, so any required function
3234 should be called by the same code after it closes the dialog.
3235 icon String A CSS class that provides a background image to be used as an icon for
3236 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3237 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3238 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3239 modal Boolean False to allow user interaction with the page while the message box is
3240 displayed (defaults to true)
3241 msg String A string that will replace the existing message box body text (defaults
3242 to the XHTML-compliant non-breaking space character ' ')
3243 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3244 progress Boolean True to display a progress bar (defaults to false)
3245 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3246 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3247 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3248 title String The title text
3249 value String The string value to set into the active textbox element if displayed
3250 wait Boolean True to display a progress bar (defaults to false)
3251 width Number The width of the dialog in pixels
3258 msg: 'Please enter your address:',
3260 buttons: Roo.MessageBox.OKCANCEL,
3263 animEl: 'addAddressBtn'
3266 * @param {Object} config Configuration options
3267 * @return {Roo.MessageBox} This message box
3269 show : function(options)
3272 // this causes nightmares if you show one dialog after another
3273 // especially on callbacks..
3275 if(this.isVisible()){
3278 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3279 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3280 Roo.log("New Dialog Message:" + options.msg )
3281 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3282 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3285 var d = this.getDialog();
3287 d.setTitle(opt.title || " ");
3288 d.closeEl.setDisplayed(opt.closable !== false);
3289 activeTextEl = textboxEl;
3290 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3295 textareaEl.setHeight(typeof opt.multiline == "number" ?
3296 opt.multiline : this.defaultTextHeight);
3297 activeTextEl = textareaEl;
3306 progressEl.setDisplayed(opt.progress === true);
3307 this.updateProgress(0);
3308 activeTextEl.dom.value = opt.value || "";
3310 dlg.setDefaultButton(activeTextEl);
3312 var bs = opt.buttons;
3316 }else if(bs && bs.yes){
3317 db = buttons["yes"];
3319 dlg.setDefaultButton(db);
3321 bwidth = updateButtons(opt.buttons);
3322 this.updateText(opt.msg);
3324 d.el.addClass(opt.cls);
3326 d.proxyDrag = opt.proxyDrag === true;
3327 d.modal = opt.modal !== false;
3328 d.mask = opt.modal !== false ? mask : false;
3330 // force it to the end of the z-index stack so it gets a cursor in FF
3331 document.body.appendChild(dlg.el.dom);
3332 d.animateTarget = null;
3333 d.show(options.animEl);
3339 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3340 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3341 * and closing the message box when the process is complete.
3342 * @param {String} title The title bar text
3343 * @param {String} msg The message box body text
3344 * @return {Roo.MessageBox} This message box
3346 progress : function(title, msg){
3353 minWidth: this.minProgressWidth,
3360 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3361 * If a callback function is passed it will be called after the user clicks the button, and the
3362 * id of the button that was clicked will be passed as the only parameter to the callback
3363 * (could also be the top-right close button).
3364 * @param {String} title The title bar text
3365 * @param {String} msg The message box body text
3366 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3367 * @param {Object} scope (optional) The scope of the callback function
3368 * @return {Roo.MessageBox} This message box
3370 alert : function(title, msg, fn, scope)
3385 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3386 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3387 * You are responsible for closing the message box when the process is complete.
3388 * @param {String} msg The message box body text
3389 * @param {String} title (optional) The title bar text
3390 * @return {Roo.MessageBox} This message box
3392 wait : function(msg, title){
3403 waitTimer = Roo.TaskMgr.start({
3405 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3413 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3414 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3415 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3416 * @param {String} title The title bar text
3417 * @param {String} msg The message box body text
3418 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3419 * @param {Object} scope (optional) The scope of the callback function
3420 * @return {Roo.MessageBox} This message box
3422 confirm : function(title, msg, fn, scope){
3426 buttons: this.YESNO,
3435 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3436 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3437 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3438 * (could also be the top-right close button) and the text that was entered will be passed as the two
3439 * parameters to the callback.
3440 * @param {String} title The title bar text
3441 * @param {String} msg The message box body text
3442 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3443 * @param {Object} scope (optional) The scope of the callback function
3444 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3445 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3446 * @return {Roo.MessageBox} This message box
3448 prompt : function(title, msg, fn, scope, multiline){
3452 buttons: this.OKCANCEL,
3457 multiline: multiline,
3464 * Button config that displays a single OK button
3469 * Button config that displays Yes and No buttons
3472 YESNO : {yes:true, no:true},
3474 * Button config that displays OK and Cancel buttons
3477 OKCANCEL : {ok:true, cancel:true},
3479 * Button config that displays Yes, No and Cancel buttons
3482 YESNOCANCEL : {yes:true, no:true, cancel:true},
3485 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3488 defaultTextHeight : 75,
3490 * The maximum width in pixels of the message box (defaults to 600)
3495 * The minimum width in pixels of the message box (defaults to 100)
3500 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3501 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3504 minProgressWidth : 250,
3506 * An object containing the default button text strings that can be overriden for localized language support.
3507 * Supported properties are: ok, cancel, yes and no.
3508 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3521 * Shorthand for {@link Roo.MessageBox}
3523 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3524 Roo.Msg = Roo.Msg || Roo.MessageBox;
3533 * @class Roo.bootstrap.Navbar
3534 * @extends Roo.bootstrap.Component
3535 * Bootstrap Navbar class
3538 * Create a new Navbar
3539 * @param {Object} config The config object
3543 Roo.bootstrap.Navbar = function(config){
3544 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3548 * @event beforetoggle
3549 * Fire before toggle the menu
3550 * @param {Roo.EventObject} e
3552 "beforetoggle" : true
3556 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3565 getAutoCreate : function(){
3568 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3572 initEvents :function ()
3574 //Roo.log(this.el.select('.navbar-toggle',true));
3575 this.el.select('.navbar-toggle',true).on('click', function() {
3576 if(this.fireEvent('beforetoggle', this) !== false){
3577 this.el.select('.navbar-collapse',true).toggleClass('in');
3587 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3589 var size = this.el.getSize();
3590 this.maskEl.setSize(size.width, size.height);
3591 this.maskEl.enableDisplayMode("block");
3600 getChildContainer : function()
3602 if (this.el.select('.collapse').getCount()) {
3603 return this.el.select('.collapse',true).first();
3636 * @class Roo.bootstrap.NavSimplebar
3637 * @extends Roo.bootstrap.Navbar
3638 * Bootstrap Sidebar class
3640 * @cfg {Boolean} inverse is inverted color
3642 * @cfg {String} type (nav | pills | tabs)
3643 * @cfg {Boolean} arrangement stacked | justified
3644 * @cfg {String} align (left | right) alignment
3646 * @cfg {Boolean} main (true|false) main nav bar? default false
3647 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3649 * @cfg {String} tag (header|footer|nav|div) default is nav
3655 * Create a new Sidebar
3656 * @param {Object} config The config object
3660 Roo.bootstrap.NavSimplebar = function(config){
3661 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3664 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3680 getAutoCreate : function(){
3684 tag : this.tag || 'div',
3697 this.type = this.type || 'nav';
3698 if (['tabs','pills'].indexOf(this.type)!==-1) {
3699 cfg.cn[0].cls += ' nav-' + this.type
3703 if (this.type!=='nav') {
3704 Roo.log('nav type must be nav/tabs/pills')
3706 cfg.cn[0].cls += ' navbar-nav'
3712 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3713 cfg.cn[0].cls += ' nav-' + this.arrangement;
3717 if (this.align === 'right') {
3718 cfg.cn[0].cls += ' navbar-right';
3722 cfg.cls += ' navbar-inverse';
3749 * @class Roo.bootstrap.NavHeaderbar
3750 * @extends Roo.bootstrap.NavSimplebar
3751 * Bootstrap Sidebar class
3753 * @cfg {String} brand what is brand
3754 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3755 * @cfg {String} brand_href href of the brand
3756 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3757 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3758 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3759 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3762 * Create a new Sidebar
3763 * @param {Object} config The config object
3767 Roo.bootstrap.NavHeaderbar = function(config){
3768 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3772 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3779 desktopCenter : false,
3782 getAutoCreate : function(){
3785 tag: this.nav || 'nav',
3792 if (this.desktopCenter) {
3793 cn.push({cls : 'container', cn : []});
3800 cls: 'navbar-header',
3805 cls: 'navbar-toggle',
3806 'data-toggle': 'collapse',
3811 html: 'Toggle navigation'
3833 cls: 'collapse navbar-collapse',
3837 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3839 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3840 cfg.cls += ' navbar-' + this.position;
3842 // tag can override this..
3844 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3847 if (this.brand !== '') {
3850 href: this.brand_href ? this.brand_href : '#',
3851 cls: 'navbar-brand',
3859 cfg.cls += ' main-nav';
3867 getHeaderChildContainer : function()
3869 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3870 return this.el.select('.navbar-header',true).first();
3873 return this.getChildContainer();
3877 initEvents : function()
3879 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3881 if (this.autohide) {
3886 Roo.get(document).on('scroll',function(e) {
3887 var ns = Roo.get(document).getScroll().top;
3888 var os = prevScroll;
3892 ft.removeClass('slideDown');
3893 ft.addClass('slideUp');
3896 ft.removeClass('slideUp');
3897 ft.addClass('slideDown');
3918 * @class Roo.bootstrap.NavSidebar
3919 * @extends Roo.bootstrap.Navbar
3920 * Bootstrap Sidebar class
3923 * Create a new Sidebar
3924 * @param {Object} config The config object
3928 Roo.bootstrap.NavSidebar = function(config){
3929 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3932 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3934 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3936 getAutoCreate : function(){
3941 cls: 'sidebar sidebar-nav'
3963 * @class Roo.bootstrap.NavGroup
3964 * @extends Roo.bootstrap.Component
3965 * Bootstrap NavGroup class
3966 * @cfg {String} align (left|right)
3967 * @cfg {Boolean} inverse
3968 * @cfg {String} type (nav|pills|tab) default nav
3969 * @cfg {String} navId - reference Id for navbar.
3973 * Create a new nav group
3974 * @param {Object} config The config object
3977 Roo.bootstrap.NavGroup = function(config){
3978 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3981 Roo.bootstrap.NavGroup.register(this);
3985 * Fires when the active item changes
3986 * @param {Roo.bootstrap.NavGroup} this
3987 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3988 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3995 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4006 getAutoCreate : function()
4008 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4015 if (['tabs','pills'].indexOf(this.type)!==-1) {
4016 cfg.cls += ' nav-' + this.type
4018 if (this.type!=='nav') {
4019 Roo.log('nav type must be nav/tabs/pills')
4021 cfg.cls += ' navbar-nav'
4024 if (this.parent().sidebar) {
4027 cls: 'dashboard-menu sidebar-menu'
4033 if (this.form === true) {
4039 if (this.align === 'right') {
4040 cfg.cls += ' navbar-right';
4042 cfg.cls += ' navbar-left';
4046 if (this.align === 'right') {
4047 cfg.cls += ' navbar-right';
4051 cfg.cls += ' navbar-inverse';
4059 * sets the active Navigation item
4060 * @param {Roo.bootstrap.NavItem} the new current navitem
4062 setActiveItem : function(item)
4065 Roo.each(this.navItems, function(v){
4070 v.setActive(false, true);
4077 item.setActive(true, true);
4078 this.fireEvent('changed', this, item, prev);
4083 * gets the active Navigation item
4084 * @return {Roo.bootstrap.NavItem} the current navitem
4086 getActive : function()
4090 Roo.each(this.navItems, function(v){
4101 indexOfNav : function()
4105 Roo.each(this.navItems, function(v,i){
4116 * adds a Navigation item
4117 * @param {Roo.bootstrap.NavItem} the navitem to add
4119 addItem : function(cfg)
4121 var cn = new Roo.bootstrap.NavItem(cfg);
4123 cn.parentId = this.id;
4124 cn.onRender(this.el, null);
4128 * register a Navigation item
4129 * @param {Roo.bootstrap.NavItem} the navitem to add
4131 register : function(item)
4133 this.navItems.push( item);
4134 item.navId = this.navId;
4139 * clear all the Navigation item
4142 clearAll : function()
4145 this.el.dom.innerHTML = '';
4148 getNavItem: function(tabId)
4151 Roo.each(this.navItems, function(e) {
4152 if (e.tabId == tabId) {
4162 setActiveNext : function()
4164 var i = this.indexOfNav(this.getActive());
4165 if (i > this.navItems.length) {
4168 this.setActiveItem(this.navItems[i+1]);
4170 setActivePrev : function()
4172 var i = this.indexOfNav(this.getActive());
4176 this.setActiveItem(this.navItems[i-1]);
4178 clearWasActive : function(except) {
4179 Roo.each(this.navItems, function(e) {
4180 if (e.tabId != except.tabId && e.was_active) {
4181 e.was_active = false;
4188 getWasActive : function ()
4191 Roo.each(this.navItems, function(e) {
4206 Roo.apply(Roo.bootstrap.NavGroup, {
4210 * register a Navigation Group
4211 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4213 register : function(navgrp)
4215 this.groups[navgrp.navId] = navgrp;
4219 * fetch a Navigation Group based on the navigation ID
4220 * @param {string} the navgroup to add
4221 * @returns {Roo.bootstrap.NavGroup} the navgroup
4223 get: function(navId) {
4224 if (typeof(this.groups[navId]) == 'undefined') {
4226 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4228 return this.groups[navId] ;
4243 * @class Roo.bootstrap.NavItem
4244 * @extends Roo.bootstrap.Component
4245 * Bootstrap Navbar.NavItem class
4246 * @cfg {String} href link to
4247 * @cfg {String} html content of button
4248 * @cfg {String} badge text inside badge
4249 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4250 * @cfg {String} glyphicon name of glyphicon
4251 * @cfg {String} icon name of font awesome icon
4252 * @cfg {Boolean} active Is item active
4253 * @cfg {Boolean} disabled Is item disabled
4255 * @cfg {Boolean} preventDefault (true | false) default false
4256 * @cfg {String} tabId the tab that this item activates.
4257 * @cfg {String} tagtype (a|span) render as a href or span?
4258 * @cfg {Boolean} animateRef (true|false) link to element default false
4261 * Create a new Navbar Item
4262 * @param {Object} config The config object
4264 Roo.bootstrap.NavItem = function(config){
4265 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4270 * The raw click event for the entire grid.
4271 * @param {Roo.EventObject} e
4276 * Fires when the active item active state changes
4277 * @param {Roo.bootstrap.NavItem} this
4278 * @param {boolean} state the new state
4284 * Fires when scroll to element
4285 * @param {Roo.bootstrap.NavItem} this
4286 * @param {Object} options
4287 * @param {Roo.EventObject} e
4295 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4303 preventDefault : false,
4310 getAutoCreate : function(){
4319 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4321 if (this.disabled) {
4322 cfg.cls += ' disabled';
4325 if (this.href || this.html || this.glyphicon || this.icon) {
4329 href : this.href || "#",
4330 html: this.html || ''
4335 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4338 if(this.glyphicon) {
4339 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4344 cfg.cn[0].html += " <span class='caret'></span>";
4348 if (this.badge !== '') {
4350 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4358 initEvents: function()
4360 if (typeof (this.menu) != 'undefined') {
4361 this.menu.parentType = this.xtype;
4362 this.menu.triggerEl = this.el;
4363 this.menu = this.addxtype(Roo.apply({}, this.menu));
4366 this.el.select('a',true).on('click', this.onClick, this);
4368 if(this.tagtype == 'span'){
4369 this.el.select('span',true).on('click', this.onClick, this);
4372 // at this point parent should be available..
4373 this.parent().register(this);
4376 onClick : function(e)
4378 if (e.getTarget('.dropdown-menu-item')) {
4379 // did you click on a menu itemm.... - then don't trigger onclick..
4384 this.preventDefault ||
4387 Roo.log("NavItem - prevent Default?");
4391 if (this.disabled) {
4395 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4396 if (tg && tg.transition) {
4397 Roo.log("waiting for the transitionend");
4403 //Roo.log("fire event clicked");
4404 if(this.fireEvent('click', this, e) === false){
4408 if(this.tagtype == 'span'){
4412 //Roo.log(this.href);
4413 var ael = this.el.select('a',true).first();
4416 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4417 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4418 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4419 return; // ignore... - it's a 'hash' to another page.
4421 Roo.log("NavItem - prevent Default?");
4423 this.scrollToElement(e);
4427 var p = this.parent();
4429 if (['tabs','pills'].indexOf(p.type)!==-1) {
4430 if (typeof(p.setActiveItem) !== 'undefined') {
4431 p.setActiveItem(this);
4435 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4436 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4437 // remove the collapsed menu expand...
4438 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4442 isActive: function () {
4445 setActive : function(state, fire, is_was_active)
4447 if (this.active && !state && this.navId) {
4448 this.was_active = true;
4449 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4451 nv.clearWasActive(this);
4455 this.active = state;
4458 this.el.removeClass('active');
4459 } else if (!this.el.hasClass('active')) {
4460 this.el.addClass('active');
4463 this.fireEvent('changed', this, state);
4466 // show a panel if it's registered and related..
4468 if (!this.navId || !this.tabId || !state || is_was_active) {
4472 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4476 var pan = tg.getPanelByName(this.tabId);
4480 // if we can not flip to new panel - go back to old nav highlight..
4481 if (false == tg.showPanel(pan)) {
4482 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4484 var onav = nv.getWasActive();
4486 onav.setActive(true, false, true);
4495 // this should not be here...
4496 setDisabled : function(state)
4498 this.disabled = state;
4500 this.el.removeClass('disabled');
4501 } else if (!this.el.hasClass('disabled')) {
4502 this.el.addClass('disabled');
4508 * Fetch the element to display the tooltip on.
4509 * @return {Roo.Element} defaults to this.el
4511 tooltipEl : function()
4513 return this.el.select('' + this.tagtype + '', true).first();
4516 scrollToElement : function(e)
4518 var c = document.body;
4521 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4523 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4524 c = document.documentElement;
4527 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4533 var o = target.calcOffsetsTo(c);
4540 this.fireEvent('scrollto', this, options, e);
4542 Roo.get(c).scrollTo('top', options.value, true);
4555 * <span> icon </span>
4556 * <span> text </span>
4557 * <span>badge </span>
4561 * @class Roo.bootstrap.NavSidebarItem
4562 * @extends Roo.bootstrap.NavItem
4563 * Bootstrap Navbar.NavSidebarItem class
4564 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4565 * {bool} open is the menu open
4567 * Create a new Navbar Button
4568 * @param {Object} config The config object
4570 Roo.bootstrap.NavSidebarItem = function(config){
4571 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4576 * The raw click event for the entire grid.
4577 * @param {Roo.EventObject} e
4582 * Fires when the active item active state changes
4583 * @param {Roo.bootstrap.NavSidebarItem} this
4584 * @param {boolean} state the new state
4592 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4594 badgeWeight : 'default',
4598 getAutoCreate : function(){
4603 href : this.href || '#',
4615 html : this.html || ''
4620 cfg.cls += ' active';
4623 if (this.disabled) {
4624 cfg.cls += ' disabled';
4627 cfg.cls += ' open x-open';
4630 if (this.glyphicon || this.icon) {
4631 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4632 a.cn.push({ tag : 'i', cls : c }) ;
4637 if (this.badge !== '') {
4639 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4643 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4644 a.cls += 'dropdown-toggle treeview' ;
4652 initEvents : function()
4654 if (typeof (this.menu) != 'undefined') {
4655 this.menu.parentType = this.xtype;
4656 this.menu.triggerEl = this.el;
4657 this.menu = this.addxtype(Roo.apply({}, this.menu));
4660 this.el.on('click', this.onClick, this);
4663 if(this.badge !== ''){
4665 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4670 onClick : function(e)
4677 if(this.preventDefault){
4681 this.fireEvent('click', this);
4684 disable : function()
4686 this.setDisabled(true);
4691 this.setDisabled(false);
4694 setDisabled : function(state)
4696 if(this.disabled == state){
4700 this.disabled = state;
4703 this.el.addClass('disabled');
4707 this.el.removeClass('disabled');
4712 setActive : function(state)
4714 if(this.active == state){
4718 this.active = state;
4721 this.el.addClass('active');
4725 this.el.removeClass('active');
4730 isActive: function ()
4735 setBadge : function(str)
4741 this.badgeEl.dom.innerHTML = str;
4758 * @class Roo.bootstrap.Row
4759 * @extends Roo.bootstrap.Component
4760 * Bootstrap Row class (contains columns...)
4764 * @param {Object} config The config object
4767 Roo.bootstrap.Row = function(config){
4768 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4771 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4773 getAutoCreate : function(){
4792 * @class Roo.bootstrap.Element
4793 * @extends Roo.bootstrap.Component
4794 * Bootstrap Element class
4795 * @cfg {String} html contents of the element
4796 * @cfg {String} tag tag of the element
4797 * @cfg {String} cls class of the element
4798 * @cfg {Boolean} preventDefault (true|false) default false
4799 * @cfg {Boolean} clickable (true|false) default false
4802 * Create a new Element
4803 * @param {Object} config The config object
4806 Roo.bootstrap.Element = function(config){
4807 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4813 * When a element is chick
4814 * @param {Roo.bootstrap.Element} this
4815 * @param {Roo.EventObject} e
4821 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4826 preventDefault: false,
4829 getAutoCreate : function(){
4840 initEvents: function()
4842 Roo.bootstrap.Element.superclass.initEvents.call(this);
4845 this.el.on('click', this.onClick, this);
4850 onClick : function(e)
4852 if(this.preventDefault){
4856 this.fireEvent('click', this, e);
4859 getValue : function()
4861 return this.el.dom.innerHTML;
4864 setValue : function(value)
4866 this.el.dom.innerHTML = value;
4881 * @class Roo.bootstrap.Pagination
4882 * @extends Roo.bootstrap.Component
4883 * Bootstrap Pagination class
4884 * @cfg {String} size xs | sm | md | lg
4885 * @cfg {Boolean} inverse false | true
4888 * Create a new Pagination
4889 * @param {Object} config The config object
4892 Roo.bootstrap.Pagination = function(config){
4893 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4896 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4902 getAutoCreate : function(){
4908 cfg.cls += ' inverse';
4914 cfg.cls += " " + this.cls;
4932 * @class Roo.bootstrap.PaginationItem
4933 * @extends Roo.bootstrap.Component
4934 * Bootstrap PaginationItem class
4935 * @cfg {String} html text
4936 * @cfg {String} href the link
4937 * @cfg {Boolean} preventDefault (true | false) default true
4938 * @cfg {Boolean} active (true | false) default false
4939 * @cfg {Boolean} disabled default false
4943 * Create a new PaginationItem
4944 * @param {Object} config The config object
4948 Roo.bootstrap.PaginationItem = function(config){
4949 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4954 * The raw click event for the entire grid.
4955 * @param {Roo.EventObject} e
4961 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4965 preventDefault: true,
4970 getAutoCreate : function(){
4976 href : this.href ? this.href : '#',
4977 html : this.html ? this.html : ''
4987 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4991 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4997 initEvents: function() {
4999 this.el.on('click', this.onClick, this);
5002 onClick : function(e)
5004 Roo.log('PaginationItem on click ');
5005 if(this.preventDefault){
5013 this.fireEvent('click', this, e);
5029 * @class Roo.bootstrap.Slider
5030 * @extends Roo.bootstrap.Component
5031 * Bootstrap Slider class
5034 * Create a new Slider
5035 * @param {Object} config The config object
5038 Roo.bootstrap.Slider = function(config){
5039 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5042 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5044 getAutoCreate : function(){
5048 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5052 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5064 * Ext JS Library 1.1.1
5065 * Copyright(c) 2006-2007, Ext JS, LLC.
5067 * Originally Released Under LGPL - original licence link has changed is not relivant.
5070 * <script type="text/javascript">
5075 * @class Roo.grid.ColumnModel
5076 * @extends Roo.util.Observable
5077 * This is the default implementation of a ColumnModel used by the Grid. It defines
5078 * the columns in the grid.
5081 var colModel = new Roo.grid.ColumnModel([
5082 {header: "Ticker", width: 60, sortable: true, locked: true},
5083 {header: "Company Name", width: 150, sortable: true},
5084 {header: "Market Cap.", width: 100, sortable: true},
5085 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5086 {header: "Employees", width: 100, sortable: true, resizable: false}
5091 * The config options listed for this class are options which may appear in each
5092 * individual column definition.
5093 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5095 * @param {Object} config An Array of column config objects. See this class's
5096 * config objects for details.
5098 Roo.grid.ColumnModel = function(config){
5100 * The config passed into the constructor
5102 this.config = config;
5105 // if no id, create one
5106 // if the column does not have a dataIndex mapping,
5107 // map it to the order it is in the config
5108 for(var i = 0, len = config.length; i < len; i++){
5110 if(typeof c.dataIndex == "undefined"){
5113 if(typeof c.renderer == "string"){
5114 c.renderer = Roo.util.Format[c.renderer];
5116 if(typeof c.id == "undefined"){
5119 if(c.editor && c.editor.xtype){
5120 c.editor = Roo.factory(c.editor, Roo.grid);
5122 if(c.editor && c.editor.isFormField){
5123 c.editor = new Roo.grid.GridEditor(c.editor);
5125 this.lookup[c.id] = c;
5129 * The width of columns which have no width specified (defaults to 100)
5132 this.defaultWidth = 100;
5135 * Default sortable of columns which have no sortable specified (defaults to false)
5138 this.defaultSortable = false;
5142 * @event widthchange
5143 * Fires when the width of a column changes.
5144 * @param {ColumnModel} this
5145 * @param {Number} columnIndex The column index
5146 * @param {Number} newWidth The new width
5148 "widthchange": true,
5150 * @event headerchange
5151 * Fires when the text of a header changes.
5152 * @param {ColumnModel} this
5153 * @param {Number} columnIndex The column index
5154 * @param {Number} newText The new header text
5156 "headerchange": true,
5158 * @event hiddenchange
5159 * Fires when a column is hidden or "unhidden".
5160 * @param {ColumnModel} this
5161 * @param {Number} columnIndex The column index
5162 * @param {Boolean} hidden true if hidden, false otherwise
5164 "hiddenchange": true,
5166 * @event columnmoved
5167 * Fires when a column is moved.
5168 * @param {ColumnModel} this
5169 * @param {Number} oldIndex
5170 * @param {Number} newIndex
5172 "columnmoved" : true,
5174 * @event columlockchange
5175 * Fires when a column's locked state is changed
5176 * @param {ColumnModel} this
5177 * @param {Number} colIndex
5178 * @param {Boolean} locked true if locked
5180 "columnlockchange" : true
5182 Roo.grid.ColumnModel.superclass.constructor.call(this);
5184 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5186 * @cfg {String} header The header text to display in the Grid view.
5189 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5190 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5191 * specified, the column's index is used as an index into the Record's data Array.
5194 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5195 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5198 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5199 * Defaults to the value of the {@link #defaultSortable} property.
5200 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5203 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5206 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5209 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5212 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5215 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5216 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5217 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5218 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5221 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5224 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5227 * @cfg {String} cursor (Optional)
5230 * @cfg {String} tooltip (Optional)
5233 * @cfg {Number} xs (Optional)
5236 * @cfg {Number} sm (Optional)
5239 * @cfg {Number} md (Optional)
5242 * @cfg {Number} lg (Optional)
5245 * Returns the id of the column at the specified index.
5246 * @param {Number} index The column index
5247 * @return {String} the id
5249 getColumnId : function(index){
5250 return this.config[index].id;
5254 * Returns the column for a specified id.
5255 * @param {String} id The column id
5256 * @return {Object} the column
5258 getColumnById : function(id){
5259 return this.lookup[id];
5264 * Returns the column for a specified dataIndex.
5265 * @param {String} dataIndex The column dataIndex
5266 * @return {Object|Boolean} the column or false if not found
5268 getColumnByDataIndex: function(dataIndex){
5269 var index = this.findColumnIndex(dataIndex);
5270 return index > -1 ? this.config[index] : false;
5274 * Returns the index for a specified column id.
5275 * @param {String} id The column id
5276 * @return {Number} the index, or -1 if not found
5278 getIndexById : function(id){
5279 for(var i = 0, len = this.config.length; i < len; i++){
5280 if(this.config[i].id == id){
5288 * Returns the index for a specified column dataIndex.
5289 * @param {String} dataIndex The column dataIndex
5290 * @return {Number} the index, or -1 if not found
5293 findColumnIndex : function(dataIndex){
5294 for(var i = 0, len = this.config.length; i < len; i++){
5295 if(this.config[i].dataIndex == dataIndex){
5303 moveColumn : function(oldIndex, newIndex){
5304 var c = this.config[oldIndex];
5305 this.config.splice(oldIndex, 1);
5306 this.config.splice(newIndex, 0, c);
5307 this.dataMap = null;
5308 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5311 isLocked : function(colIndex){
5312 return this.config[colIndex].locked === true;
5315 setLocked : function(colIndex, value, suppressEvent){
5316 if(this.isLocked(colIndex) == value){
5319 this.config[colIndex].locked = value;
5321 this.fireEvent("columnlockchange", this, colIndex, value);
5325 getTotalLockedWidth : function(){
5327 for(var i = 0; i < this.config.length; i++){
5328 if(this.isLocked(i) && !this.isHidden(i)){
5329 this.totalWidth += this.getColumnWidth(i);
5335 getLockedCount : function(){
5336 for(var i = 0, len = this.config.length; i < len; i++){
5337 if(!this.isLocked(i)){
5342 return this.config.length;
5346 * Returns the number of columns.
5349 getColumnCount : function(visibleOnly){
5350 if(visibleOnly === true){
5352 for(var i = 0, len = this.config.length; i < len; i++){
5353 if(!this.isHidden(i)){
5359 return this.config.length;
5363 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5364 * @param {Function} fn
5365 * @param {Object} scope (optional)
5366 * @return {Array} result
5368 getColumnsBy : function(fn, scope){
5370 for(var i = 0, len = this.config.length; i < len; i++){
5371 var c = this.config[i];
5372 if(fn.call(scope||this, c, i) === true){
5380 * Returns true if the specified column is sortable.
5381 * @param {Number} col The column index
5384 isSortable : function(col){
5385 if(typeof this.config[col].sortable == "undefined"){
5386 return this.defaultSortable;
5388 return this.config[col].sortable;
5392 * Returns the rendering (formatting) function defined for the column.
5393 * @param {Number} col The column index.
5394 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5396 getRenderer : function(col){
5397 if(!this.config[col].renderer){
5398 return Roo.grid.ColumnModel.defaultRenderer;
5400 return this.config[col].renderer;
5404 * Sets the rendering (formatting) function for a column.
5405 * @param {Number} col The column index
5406 * @param {Function} fn The function to use to process the cell's raw data
5407 * to return HTML markup for the grid view. The render function is called with
5408 * the following parameters:<ul>
5409 * <li>Data value.</li>
5410 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5411 * <li>css A CSS style string to apply to the table cell.</li>
5412 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5413 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5414 * <li>Row index</li>
5415 * <li>Column index</li>
5416 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5418 setRenderer : function(col, fn){
5419 this.config[col].renderer = fn;
5423 * Returns the width for the specified column.
5424 * @param {Number} col The column index
5427 getColumnWidth : function(col){
5428 return this.config[col].width * 1 || this.defaultWidth;
5432 * Sets the width for a column.
5433 * @param {Number} col The column index
5434 * @param {Number} width The new width
5436 setColumnWidth : function(col, width, suppressEvent){
5437 this.config[col].width = width;
5438 this.totalWidth = null;
5440 this.fireEvent("widthchange", this, col, width);
5445 * Returns the total width of all columns.
5446 * @param {Boolean} includeHidden True to include hidden column widths
5449 getTotalWidth : function(includeHidden){
5450 if(!this.totalWidth){
5451 this.totalWidth = 0;
5452 for(var i = 0, len = this.config.length; i < len; i++){
5453 if(includeHidden || !this.isHidden(i)){
5454 this.totalWidth += this.getColumnWidth(i);
5458 return this.totalWidth;
5462 * Returns the header for the specified column.
5463 * @param {Number} col The column index
5466 getColumnHeader : function(col){
5467 return this.config[col].header;
5471 * Sets the header for a column.
5472 * @param {Number} col The column index
5473 * @param {String} header The new header
5475 setColumnHeader : function(col, header){
5476 this.config[col].header = header;
5477 this.fireEvent("headerchange", this, col, header);
5481 * Returns the tooltip for the specified column.
5482 * @param {Number} col The column index
5485 getColumnTooltip : function(col){
5486 return this.config[col].tooltip;
5489 * Sets the tooltip for a column.
5490 * @param {Number} col The column index
5491 * @param {String} tooltip The new tooltip
5493 setColumnTooltip : function(col, tooltip){
5494 this.config[col].tooltip = tooltip;
5498 * Returns the dataIndex for the specified column.
5499 * @param {Number} col The column index
5502 getDataIndex : function(col){
5503 return this.config[col].dataIndex;
5507 * Sets the dataIndex for a column.
5508 * @param {Number} col The column index
5509 * @param {Number} dataIndex The new dataIndex
5511 setDataIndex : function(col, dataIndex){
5512 this.config[col].dataIndex = dataIndex;
5518 * Returns true if the cell is editable.
5519 * @param {Number} colIndex The column index
5520 * @param {Number} rowIndex The row index - this is nto actually used..?
5523 isCellEditable : function(colIndex, rowIndex){
5524 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5528 * Returns the editor defined for the cell/column.
5529 * return false or null to disable editing.
5530 * @param {Number} colIndex The column index
5531 * @param {Number} rowIndex The row index
5534 getCellEditor : function(colIndex, rowIndex){
5535 return this.config[colIndex].editor;
5539 * Sets if a column is editable.
5540 * @param {Number} col The column index
5541 * @param {Boolean} editable True if the column is editable
5543 setEditable : function(col, editable){
5544 this.config[col].editable = editable;
5549 * Returns true if the column is hidden.
5550 * @param {Number} colIndex The column index
5553 isHidden : function(colIndex){
5554 return this.config[colIndex].hidden;
5559 * Returns true if the column width cannot be changed
5561 isFixed : function(colIndex){
5562 return this.config[colIndex].fixed;
5566 * Returns true if the column can be resized
5569 isResizable : function(colIndex){
5570 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5573 * Sets if a column is hidden.
5574 * @param {Number} colIndex The column index
5575 * @param {Boolean} hidden True if the column is hidden
5577 setHidden : function(colIndex, hidden){
5578 this.config[colIndex].hidden = hidden;
5579 this.totalWidth = null;
5580 this.fireEvent("hiddenchange", this, colIndex, hidden);
5584 * Sets the editor for a column.
5585 * @param {Number} col The column index
5586 * @param {Object} editor The editor object
5588 setEditor : function(col, editor){
5589 this.config[col].editor = editor;
5593 Roo.grid.ColumnModel.defaultRenderer = function(value)
5595 if(typeof value == "object") {
5598 if(typeof value == "string" && value.length < 1){
5602 return String.format("{0}", value);
5605 // Alias for backwards compatibility
5606 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5609 * Ext JS Library 1.1.1
5610 * Copyright(c) 2006-2007, Ext JS, LLC.
5612 * Originally Released Under LGPL - original licence link has changed is not relivant.
5615 * <script type="text/javascript">
5619 * @class Roo.LoadMask
5620 * A simple utility class for generically masking elements while loading data. If the element being masked has
5621 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5622 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5623 * element's UpdateManager load indicator and will be destroyed after the initial load.
5625 * Create a new LoadMask
5626 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5627 * @param {Object} config The config object
5629 Roo.LoadMask = function(el, config){
5630 this.el = Roo.get(el);
5631 Roo.apply(this, config);
5633 this.store.on('beforeload', this.onBeforeLoad, this);
5634 this.store.on('load', this.onLoad, this);
5635 this.store.on('loadexception', this.onLoadException, this);
5636 this.removeMask = false;
5638 var um = this.el.getUpdateManager();
5639 um.showLoadIndicator = false; // disable the default indicator
5640 um.on('beforeupdate', this.onBeforeLoad, this);
5641 um.on('update', this.onLoad, this);
5642 um.on('failure', this.onLoad, this);
5643 this.removeMask = true;
5647 Roo.LoadMask.prototype = {
5649 * @cfg {Boolean} removeMask
5650 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5651 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5655 * The text to display in a centered loading message box (defaults to 'Loading...')
5659 * @cfg {String} msgCls
5660 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5662 msgCls : 'x-mask-loading',
5665 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5671 * Disables the mask to prevent it from being displayed
5673 disable : function(){
5674 this.disabled = true;
5678 * Enables the mask so that it can be displayed
5680 enable : function(){
5681 this.disabled = false;
5684 onLoadException : function()
5688 if (typeof(arguments[3]) != 'undefined') {
5689 Roo.MessageBox.alert("Error loading",arguments[3]);
5693 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5694 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5701 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5706 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5710 onBeforeLoad : function(){
5712 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5717 destroy : function(){
5719 this.store.un('beforeload', this.onBeforeLoad, this);
5720 this.store.un('load', this.onLoad, this);
5721 this.store.un('loadexception', this.onLoadException, this);
5723 var um = this.el.getUpdateManager();
5724 um.un('beforeupdate', this.onBeforeLoad, this);
5725 um.un('update', this.onLoad, this);
5726 um.un('failure', this.onLoad, this);
5737 * @class Roo.bootstrap.Table
5738 * @extends Roo.bootstrap.Component
5739 * Bootstrap Table class
5740 * @cfg {String} cls table class
5741 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5742 * @cfg {String} bgcolor Specifies the background color for a table
5743 * @cfg {Number} border Specifies whether the table cells should have borders or not
5744 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5745 * @cfg {Number} cellspacing Specifies the space between cells
5746 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5747 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5748 * @cfg {String} sortable Specifies that the table should be sortable
5749 * @cfg {String} summary Specifies a summary of the content of a table
5750 * @cfg {Number} width Specifies the width of a table
5751 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5753 * @cfg {boolean} striped Should the rows be alternative striped
5754 * @cfg {boolean} bordered Add borders to the table
5755 * @cfg {boolean} hover Add hover highlighting
5756 * @cfg {boolean} condensed Format condensed
5757 * @cfg {boolean} responsive Format condensed
5758 * @cfg {Boolean} loadMask (true|false) default false
5759 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5760 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5761 * @cfg {Boolean} rowSelection (true|false) default false
5762 * @cfg {Boolean} cellSelection (true|false) default false
5763 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5764 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5768 * Create a new Table
5769 * @param {Object} config The config object
5772 Roo.bootstrap.Table = function(config){
5773 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5778 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5779 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5780 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5781 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5783 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5785 this.sm.grid = this;
5786 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5787 this.sm = this.selModel;
5788 this.sm.xmodule = this.xmodule || false;
5791 if (this.cm && typeof(this.cm.config) == 'undefined') {
5792 this.colModel = new Roo.grid.ColumnModel(this.cm);
5793 this.cm = this.colModel;
5794 this.cm.xmodule = this.xmodule || false;
5797 this.store= Roo.factory(this.store, Roo.data);
5798 this.ds = this.store;
5799 this.ds.xmodule = this.xmodule || false;
5802 if (this.footer && this.store) {
5803 this.footer.dataSource = this.ds;
5804 this.footer = Roo.factory(this.footer);
5811 * Fires when a cell is clicked
5812 * @param {Roo.bootstrap.Table} this
5813 * @param {Roo.Element} el
5814 * @param {Number} rowIndex
5815 * @param {Number} columnIndex
5816 * @param {Roo.EventObject} e
5820 * @event celldblclick
5821 * Fires when a cell is double clicked
5822 * @param {Roo.bootstrap.Table} this
5823 * @param {Roo.Element} el
5824 * @param {Number} rowIndex
5825 * @param {Number} columnIndex
5826 * @param {Roo.EventObject} e
5828 "celldblclick" : true,
5831 * Fires when a row is clicked
5832 * @param {Roo.bootstrap.Table} this
5833 * @param {Roo.Element} el
5834 * @param {Number} rowIndex
5835 * @param {Roo.EventObject} e
5839 * @event rowdblclick
5840 * Fires when a row is double clicked
5841 * @param {Roo.bootstrap.Table} this
5842 * @param {Roo.Element} el
5843 * @param {Number} rowIndex
5844 * @param {Roo.EventObject} e
5846 "rowdblclick" : true,
5849 * Fires when a mouseover occur
5850 * @param {Roo.bootstrap.Table} this
5851 * @param {Roo.Element} el
5852 * @param {Number} rowIndex
5853 * @param {Number} columnIndex
5854 * @param {Roo.EventObject} e
5859 * Fires when a mouseout occur
5860 * @param {Roo.bootstrap.Table} this
5861 * @param {Roo.Element} el
5862 * @param {Number} rowIndex
5863 * @param {Number} columnIndex
5864 * @param {Roo.EventObject} e
5869 * Fires when a row is rendered, so you can change add a style to it.
5870 * @param {Roo.bootstrap.Table} this
5871 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5875 * @event rowsrendered
5876 * Fires when all the rows have been rendered
5877 * @param {Roo.bootstrap.Table} this
5879 'rowsrendered' : true,
5881 * @event contextmenu
5882 * The raw contextmenu event for the entire grid.
5883 * @param {Roo.EventObject} e
5885 "contextmenu" : true,
5887 * @event rowcontextmenu
5888 * Fires when a row is right clicked
5889 * @param {Roo.bootstrap.Table} this
5890 * @param {Number} rowIndex
5891 * @param {Roo.EventObject} e
5893 "rowcontextmenu" : true,
5895 * @event cellcontextmenu
5896 * Fires when a cell is right clicked
5897 * @param {Roo.bootstrap.Table} this
5898 * @param {Number} rowIndex
5899 * @param {Number} cellIndex
5900 * @param {Roo.EventObject} e
5902 "cellcontextmenu" : true,
5904 * @event headercontextmenu
5905 * Fires when a header is right clicked
5906 * @param {Roo.bootstrap.Table} this
5907 * @param {Number} columnIndex
5908 * @param {Roo.EventObject} e
5910 "headercontextmenu" : true
5914 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5940 rowSelection : false,
5941 cellSelection : false,
5944 // Roo.Element - the tbody
5946 // Roo.Element - thead element
5949 container: false, // used by gridpanel...
5951 getAutoCreate : function()
5953 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5960 if (this.scrollBody) {
5961 cfg.cls += ' table-body-fixed';
5964 cfg.cls += ' table-striped';
5968 cfg.cls += ' table-hover';
5970 if (this.bordered) {
5971 cfg.cls += ' table-bordered';
5973 if (this.condensed) {
5974 cfg.cls += ' table-condensed';
5976 if (this.responsive) {
5977 cfg.cls += ' table-responsive';
5981 cfg.cls+= ' ' +this.cls;
5984 // this lot should be simplifed...
5987 cfg.align=this.align;
5990 cfg.bgcolor=this.bgcolor;
5993 cfg.border=this.border;
5995 if (this.cellpadding) {
5996 cfg.cellpadding=this.cellpadding;
5998 if (this.cellspacing) {
5999 cfg.cellspacing=this.cellspacing;
6002 cfg.frame=this.frame;
6005 cfg.rules=this.rules;
6007 if (this.sortable) {
6008 cfg.sortable=this.sortable;
6011 cfg.summary=this.summary;
6014 cfg.width=this.width;
6017 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6020 if(this.store || this.cm){
6021 if(this.headerShow){
6022 cfg.cn.push(this.renderHeader());
6025 cfg.cn.push(this.renderBody());
6027 if(this.footerShow){
6028 cfg.cn.push(this.renderFooter());
6030 // where does this come from?
6031 //cfg.cls+= ' TableGrid';
6034 return { cn : [ cfg ] };
6037 initEvents : function()
6039 if(!this.store || !this.cm){
6042 if (this.selModel) {
6043 this.selModel.initEvents();
6047 //Roo.log('initEvents with ds!!!!');
6049 this.mainBody = this.el.select('tbody', true).first();
6050 this.mainHead = this.el.select('thead', true).first();
6057 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6058 e.on('click', _this.sort, _this);
6061 this.mainBody.on("click", this.onClick, this);
6062 this.mainBody.on("dblclick", this.onDblClick, this);
6064 // why is this done????? = it breaks dialogs??
6065 //this.parent().el.setStyle('position', 'relative');
6069 this.footer.parentId = this.id;
6070 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6073 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6075 this.store.on('load', this.onLoad, this);
6076 this.store.on('beforeload', this.onBeforeLoad, this);
6077 this.store.on('update', this.onUpdate, this);
6078 this.store.on('add', this.onAdd, this);
6079 this.store.on("clear", this.clear, this);
6081 this.el.on("contextmenu", this.onContextMenu, this);
6083 this.mainBody.on('scroll', this.onBodyScroll, this);
6088 onContextMenu : function(e, t)
6090 this.processEvent("contextmenu", e);
6093 processEvent : function(name, e)
6095 if (name != 'touchstart' ) {
6096 this.fireEvent(name, e);
6099 var t = e.getTarget();
6101 var cell = Roo.get(t);
6107 if(cell.findParent('tfoot', false, true)){
6111 if(cell.findParent('thead', false, true)){
6113 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6114 cell = Roo.get(t).findParent('th', false, true);
6116 Roo.log("failed to find th in thead?");
6117 Roo.log(e.getTarget());
6122 var cellIndex = cell.dom.cellIndex;
6124 var ename = name == 'touchstart' ? 'click' : name;
6125 this.fireEvent("header" + ename, this, cellIndex, e);
6130 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6131 cell = Roo.get(t).findParent('td', false, true);
6133 Roo.log("failed to find th in tbody?");
6134 Roo.log(e.getTarget());
6139 var row = cell.findParent('tr', false, true);
6140 var cellIndex = cell.dom.cellIndex;
6141 var rowIndex = row.dom.rowIndex - 1;
6145 this.fireEvent("row" + name, this, rowIndex, e);
6149 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6155 onMouseover : function(e, el)
6157 var cell = Roo.get(el);
6163 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6164 cell = cell.findParent('td', false, true);
6167 var row = cell.findParent('tr', false, true);
6168 var cellIndex = cell.dom.cellIndex;
6169 var rowIndex = row.dom.rowIndex - 1; // start from 0
6171 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6175 onMouseout : function(e, el)
6177 var cell = Roo.get(el);
6183 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6184 cell = cell.findParent('td', false, true);
6187 var row = cell.findParent('tr', false, true);
6188 var cellIndex = cell.dom.cellIndex;
6189 var rowIndex = row.dom.rowIndex - 1; // start from 0
6191 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6195 onClick : function(e, el)
6197 var cell = Roo.get(el);
6199 if(!cell || (!this.cellSelection && !this.rowSelection)){
6203 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6204 cell = cell.findParent('td', false, true);
6207 if(!cell || typeof(cell) == 'undefined'){
6211 var row = cell.findParent('tr', false, true);
6213 if(!row || typeof(row) == 'undefined'){
6217 var cellIndex = cell.dom.cellIndex;
6218 var rowIndex = this.getRowIndex(row);
6220 // why??? - should these not be based on SelectionModel?
6221 if(this.cellSelection){
6222 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6225 if(this.rowSelection){
6226 this.fireEvent('rowclick', this, row, rowIndex, e);
6232 onDblClick : function(e,el)
6234 var cell = Roo.get(el);
6236 if(!cell || (!this.cellSelection && !this.rowSelection)){
6240 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6241 cell = cell.findParent('td', false, true);
6244 if(!cell || typeof(cell) == 'undefined'){
6248 var row = cell.findParent('tr', false, true);
6250 if(!row || typeof(row) == 'undefined'){
6254 var cellIndex = cell.dom.cellIndex;
6255 var rowIndex = this.getRowIndex(row);
6257 if(this.cellSelection){
6258 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6261 if(this.rowSelection){
6262 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6266 sort : function(e,el)
6268 var col = Roo.get(el);
6270 if(!col.hasClass('sortable')){
6274 var sort = col.attr('sort');
6277 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6281 this.store.sortInfo = {field : sort, direction : dir};
6284 Roo.log("calling footer first");
6285 this.footer.onClick('first');
6288 this.store.load({ params : { start : 0 } });
6292 renderHeader : function()
6300 this.totalWidth = 0;
6302 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6304 var config = cm.config[i];
6309 html: cm.getColumnHeader(i)
6314 if(typeof(config.sortable) != 'undefined' && config.sortable){
6316 c.html = '<i class="glyphicon"></i>' + c.html;
6319 if(typeof(config.lgHeader) != 'undefined'){
6320 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6323 if(typeof(config.mdHeader) != 'undefined'){
6324 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6327 if(typeof(config.smHeader) != 'undefined'){
6328 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6331 if(typeof(config.xsHeader) != 'undefined'){
6332 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6339 if(typeof(config.tooltip) != 'undefined'){
6340 c.tooltip = config.tooltip;
6343 if(typeof(config.colspan) != 'undefined'){
6344 c.colspan = config.colspan;
6347 if(typeof(config.hidden) != 'undefined' && config.hidden){
6348 c.style += ' display:none;';
6351 if(typeof(config.dataIndex) != 'undefined'){
6352 c.sort = config.dataIndex;
6357 if(typeof(config.align) != 'undefined' && config.align.length){
6358 c.style += ' text-align:' + config.align + ';';
6361 if(typeof(config.width) != 'undefined'){
6362 c.style += ' width:' + config.width + 'px;';
6363 this.totalWidth += config.width;
6365 this.totalWidth += 100; // assume minimum of 100 per column?
6368 if(typeof(config.cls) != 'undefined'){
6369 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6372 ['xs','sm','md','lg'].map(function(size){
6374 if(typeof(config[size]) == 'undefined'){
6378 if (!config[size]) { // 0 = hidden
6379 c.cls += ' hidden-' + size;
6383 c.cls += ' col-' + size + '-' + config[size];
6393 renderBody : function()
6403 colspan : this.cm.getColumnCount()
6413 renderFooter : function()
6423 colspan : this.cm.getColumnCount()
6437 // Roo.log('ds onload');
6442 var ds = this.store;
6444 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6445 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6446 if (_this.store.sortInfo) {
6448 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6449 e.select('i', true).addClass(['glyphicon-arrow-up']);
6452 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6453 e.select('i', true).addClass(['glyphicon-arrow-down']);
6458 var tbody = this.mainBody;
6460 if(ds.getCount() > 0){
6461 ds.data.each(function(d,rowIndex){
6462 var row = this.renderRow(cm, ds, rowIndex);
6464 tbody.createChild(row);
6468 if(row.cellObjects.length){
6469 Roo.each(row.cellObjects, function(r){
6470 _this.renderCellObject(r);
6477 Roo.each(this.el.select('tbody td', true).elements, function(e){
6478 e.on('mouseover', _this.onMouseover, _this);
6481 Roo.each(this.el.select('tbody td', true).elements, function(e){
6482 e.on('mouseout', _this.onMouseout, _this);
6484 this.fireEvent('rowsrendered', this);
6485 //if(this.loadMask){
6486 // this.maskEl.hide();
6493 onUpdate : function(ds,record)
6495 this.refreshRow(record);
6499 onRemove : function(ds, record, index, isUpdate){
6500 if(isUpdate !== true){
6501 this.fireEvent("beforerowremoved", this, index, record);
6503 var bt = this.mainBody.dom;
6505 var rows = this.el.select('tbody > tr', true).elements;
6507 if(typeof(rows[index]) != 'undefined'){
6508 bt.removeChild(rows[index].dom);
6511 // if(bt.rows[index]){
6512 // bt.removeChild(bt.rows[index]);
6515 if(isUpdate !== true){
6516 //this.stripeRows(index);
6517 //this.syncRowHeights(index, index);
6519 this.fireEvent("rowremoved", this, index, record);
6523 onAdd : function(ds, records, rowIndex)
6525 //Roo.log('on Add called');
6526 // - note this does not handle multiple adding very well..
6527 var bt = this.mainBody.dom;
6528 for (var i =0 ; i < records.length;i++) {
6529 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6530 //Roo.log(records[i]);
6531 //Roo.log(this.store.getAt(rowIndex+i));
6532 this.insertRow(this.store, rowIndex + i, false);
6539 refreshRow : function(record){
6540 var ds = this.store, index;
6541 if(typeof record == 'number'){
6543 record = ds.getAt(index);
6545 index = ds.indexOf(record);
6547 this.insertRow(ds, index, true);
6549 this.onRemove(ds, record, index+1, true);
6551 //this.syncRowHeights(index, index);
6553 this.fireEvent("rowupdated", this, index, record);
6556 insertRow : function(dm, rowIndex, isUpdate){
6559 this.fireEvent("beforerowsinserted", this, rowIndex);
6561 //var s = this.getScrollState();
6562 var row = this.renderRow(this.cm, this.store, rowIndex);
6563 // insert before rowIndex..
6564 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6568 if(row.cellObjects.length){
6569 Roo.each(row.cellObjects, function(r){
6570 _this.renderCellObject(r);
6575 this.fireEvent("rowsinserted", this, rowIndex);
6576 //this.syncRowHeights(firstRow, lastRow);
6577 //this.stripeRows(firstRow);
6584 getRowDom : function(rowIndex)
6586 var rows = this.el.select('tbody > tr', true).elements;
6588 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6591 // returns the object tree for a tr..
6594 renderRow : function(cm, ds, rowIndex)
6597 var d = ds.getAt(rowIndex);
6604 var cellObjects = [];
6606 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6607 var config = cm.config[i];
6609 var renderer = cm.getRenderer(i);
6613 if(typeof(renderer) !== 'undefined'){
6614 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6616 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6617 // and are rendered into the cells after the row is rendered - using the id for the element.
6619 if(typeof(value) === 'object'){
6629 rowIndex : rowIndex,
6634 this.fireEvent('rowclass', this, rowcfg);
6638 cls : rowcfg.rowClass,
6640 html: (typeof(value) === 'object') ? '' : value
6647 if(typeof(config.colspan) != 'undefined'){
6648 td.colspan = config.colspan;
6651 if(typeof(config.hidden) != 'undefined' && config.hidden){
6652 td.style += ' display:none;';
6655 if(typeof(config.align) != 'undefined' && config.align.length){
6656 td.style += ' text-align:' + config.align + ';';
6659 if(typeof(config.width) != 'undefined'){
6660 td.style += ' width:' + config.width + 'px;';
6663 if(typeof(config.cursor) != 'undefined'){
6664 td.style += ' cursor:' + config.cursor + ';';
6667 if(typeof(config.cls) != 'undefined'){
6668 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6671 ['xs','sm','md','lg'].map(function(size){
6673 if(typeof(config[size]) == 'undefined'){
6677 if (!config[size]) { // 0 = hidden
6678 td.cls += ' hidden-' + size;
6682 td.cls += ' col-' + size + '-' + config[size];
6690 row.cellObjects = cellObjects;
6698 onBeforeLoad : function()
6700 //Roo.log('ds onBeforeLoad');
6704 //if(this.loadMask){
6705 // this.maskEl.show();
6713 this.el.select('tbody', true).first().dom.innerHTML = '';
6716 * Show or hide a row.
6717 * @param {Number} rowIndex to show or hide
6718 * @param {Boolean} state hide
6720 setRowVisibility : function(rowIndex, state)
6722 var bt = this.mainBody.dom;
6724 var rows = this.el.select('tbody > tr', true).elements;
6726 if(typeof(rows[rowIndex]) == 'undefined'){
6729 rows[rowIndex].dom.style.display = state ? '' : 'none';
6733 getSelectionModel : function(){
6735 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6737 return this.selModel;
6740 * Render the Roo.bootstrap object from renderder
6742 renderCellObject : function(r)
6746 var t = r.cfg.render(r.container);
6749 Roo.each(r.cfg.cn, function(c){
6751 container: t.getChildContainer(),
6754 _this.renderCellObject(child);
6759 getRowIndex : function(row)
6763 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6774 * Returns the grid's underlying element = used by panel.Grid
6775 * @return {Element} The element
6777 getGridEl : function(){
6781 * Forces a resize - used by panel.Grid
6782 * @return {Element} The element
6784 autoSize : function()
6786 //var ctr = Roo.get(this.container.dom.parentElement);
6787 var ctr = Roo.get(this.el.dom);
6789 var thd = this.getGridEl().select('thead',true).first();
6790 var tbd = this.getGridEl().select('tbody', true).first();
6791 var tfd = this.getGridEl().select('tfoot', true).first();
6793 var cw = ctr.getWidth();
6797 tbd.setSize(ctr.getWidth(),
6798 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6800 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6803 cw = Math.max(cw, this.totalWidth);
6804 this.getGridEl().select('tr',true).setWidth(cw);
6805 // resize 'expandable coloumn?
6807 return; // we doe not have a view in this design..
6810 onBodyScroll: function()
6813 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6814 this.mainHead.setStyle({
6815 'position' : 'relative',
6816 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6833 * @class Roo.bootstrap.TableCell
6834 * @extends Roo.bootstrap.Component
6835 * Bootstrap TableCell class
6836 * @cfg {String} html cell contain text
6837 * @cfg {String} cls cell class
6838 * @cfg {String} tag cell tag (td|th) default td
6839 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6840 * @cfg {String} align Aligns the content in a cell
6841 * @cfg {String} axis Categorizes cells
6842 * @cfg {String} bgcolor Specifies the background color of a cell
6843 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6844 * @cfg {Number} colspan Specifies the number of columns a cell should span
6845 * @cfg {String} headers Specifies one or more header cells a cell is related to
6846 * @cfg {Number} height Sets the height of a cell
6847 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6848 * @cfg {Number} rowspan Sets the number of rows a cell should span
6849 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6850 * @cfg {String} valign Vertical aligns the content in a cell
6851 * @cfg {Number} width Specifies the width of a cell
6854 * Create a new TableCell
6855 * @param {Object} config The config object
6858 Roo.bootstrap.TableCell = function(config){
6859 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6862 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6882 getAutoCreate : function(){
6883 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6903 cfg.align=this.align
6909 cfg.bgcolor=this.bgcolor
6912 cfg.charoff=this.charoff
6915 cfg.colspan=this.colspan
6918 cfg.headers=this.headers
6921 cfg.height=this.height
6924 cfg.nowrap=this.nowrap
6927 cfg.rowspan=this.rowspan
6930 cfg.scope=this.scope
6933 cfg.valign=this.valign
6936 cfg.width=this.width
6955 * @class Roo.bootstrap.TableRow
6956 * @extends Roo.bootstrap.Component
6957 * Bootstrap TableRow class
6958 * @cfg {String} cls row class
6959 * @cfg {String} align Aligns the content in a table row
6960 * @cfg {String} bgcolor Specifies a background color for a table row
6961 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6962 * @cfg {String} valign Vertical aligns the content in a table row
6965 * Create a new TableRow
6966 * @param {Object} config The config object
6969 Roo.bootstrap.TableRow = function(config){
6970 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6973 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6981 getAutoCreate : function(){
6982 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6992 cfg.align = this.align;
6995 cfg.bgcolor = this.bgcolor;
6998 cfg.charoff = this.charoff;
7001 cfg.valign = this.valign;
7019 * @class Roo.bootstrap.TableBody
7020 * @extends Roo.bootstrap.Component
7021 * Bootstrap TableBody class
7022 * @cfg {String} cls element class
7023 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7024 * @cfg {String} align Aligns the content inside the element
7025 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7026 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7029 * Create a new TableBody
7030 * @param {Object} config The config object
7033 Roo.bootstrap.TableBody = function(config){
7034 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7037 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7045 getAutoCreate : function(){
7046 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7060 cfg.align = this.align;
7063 cfg.charoff = this.charoff;
7066 cfg.valign = this.valign;
7073 // initEvents : function()
7080 // this.store = Roo.factory(this.store, Roo.data);
7081 // this.store.on('load', this.onLoad, this);
7083 // this.store.load();
7087 // onLoad: function ()
7089 // this.fireEvent('load', this);
7099 * Ext JS Library 1.1.1
7100 * Copyright(c) 2006-2007, Ext JS, LLC.
7102 * Originally Released Under LGPL - original licence link has changed is not relivant.
7105 * <script type="text/javascript">
7108 // as we use this in bootstrap.
7109 Roo.namespace('Roo.form');
7111 * @class Roo.form.Action
7112 * Internal Class used to handle form actions
7114 * @param {Roo.form.BasicForm} el The form element or its id
7115 * @param {Object} config Configuration options
7120 // define the action interface
7121 Roo.form.Action = function(form, options){
7123 this.options = options || {};
7126 * Client Validation Failed
7129 Roo.form.Action.CLIENT_INVALID = 'client';
7131 * Server Validation Failed
7134 Roo.form.Action.SERVER_INVALID = 'server';
7136 * Connect to Server Failed
7139 Roo.form.Action.CONNECT_FAILURE = 'connect';
7141 * Reading Data from Server Failed
7144 Roo.form.Action.LOAD_FAILURE = 'load';
7146 Roo.form.Action.prototype = {
7148 failureType : undefined,
7149 response : undefined,
7153 run : function(options){
7158 success : function(response){
7163 handleResponse : function(response){
7167 // default connection failure
7168 failure : function(response){
7170 this.response = response;
7171 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7172 this.form.afterAction(this, false);
7175 processResponse : function(response){
7176 this.response = response;
7177 if(!response.responseText){
7180 this.result = this.handleResponse(response);
7184 // utility functions used internally
7185 getUrl : function(appendParams){
7186 var url = this.options.url || this.form.url || this.form.el.dom.action;
7188 var p = this.getParams();
7190 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7196 getMethod : function(){
7197 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7200 getParams : function(){
7201 var bp = this.form.baseParams;
7202 var p = this.options.params;
7204 if(typeof p == "object"){
7205 p = Roo.urlEncode(Roo.applyIf(p, bp));
7206 }else if(typeof p == 'string' && bp){
7207 p += '&' + Roo.urlEncode(bp);
7210 p = Roo.urlEncode(bp);
7215 createCallback : function(){
7217 success: this.success,
7218 failure: this.failure,
7220 timeout: (this.form.timeout*1000),
7221 upload: this.form.fileUpload ? this.success : undefined
7226 Roo.form.Action.Submit = function(form, options){
7227 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7230 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7233 haveProgress : false,
7234 uploadComplete : false,
7236 // uploadProgress indicator.
7237 uploadProgress : function()
7239 if (!this.form.progressUrl) {
7243 if (!this.haveProgress) {
7244 Roo.MessageBox.progress("Uploading", "Uploading");
7246 if (this.uploadComplete) {
7247 Roo.MessageBox.hide();
7251 this.haveProgress = true;
7253 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7255 var c = new Roo.data.Connection();
7257 url : this.form.progressUrl,
7262 success : function(req){
7263 //console.log(data);
7267 rdata = Roo.decode(req.responseText)
7269 Roo.log("Invalid data from server..");
7273 if (!rdata || !rdata.success) {
7275 Roo.MessageBox.alert(Roo.encode(rdata));
7278 var data = rdata.data;
7280 if (this.uploadComplete) {
7281 Roo.MessageBox.hide();
7286 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7287 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7290 this.uploadProgress.defer(2000,this);
7293 failure: function(data) {
7294 Roo.log('progress url failed ');
7305 // run get Values on the form, so it syncs any secondary forms.
7306 this.form.getValues();
7308 var o = this.options;
7309 var method = this.getMethod();
7310 var isPost = method == 'POST';
7311 if(o.clientValidation === false || this.form.isValid()){
7313 if (this.form.progressUrl) {
7314 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7315 (new Date() * 1) + '' + Math.random());
7320 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7321 form:this.form.el.dom,
7322 url:this.getUrl(!isPost),
7324 params:isPost ? this.getParams() : null,
7325 isUpload: this.form.fileUpload
7328 this.uploadProgress();
7330 }else if (o.clientValidation !== false){ // client validation failed
7331 this.failureType = Roo.form.Action.CLIENT_INVALID;
7332 this.form.afterAction(this, false);
7336 success : function(response)
7338 this.uploadComplete= true;
7339 if (this.haveProgress) {
7340 Roo.MessageBox.hide();
7344 var result = this.processResponse(response);
7345 if(result === true || result.success){
7346 this.form.afterAction(this, true);
7350 this.form.markInvalid(result.errors);
7351 this.failureType = Roo.form.Action.SERVER_INVALID;
7353 this.form.afterAction(this, false);
7355 failure : function(response)
7357 this.uploadComplete= true;
7358 if (this.haveProgress) {
7359 Roo.MessageBox.hide();
7362 this.response = response;
7363 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7364 this.form.afterAction(this, false);
7367 handleResponse : function(response){
7368 if(this.form.errorReader){
7369 var rs = this.form.errorReader.read(response);
7372 for(var i = 0, len = rs.records.length; i < len; i++) {
7373 var r = rs.records[i];
7377 if(errors.length < 1){
7381 success : rs.success,
7387 ret = Roo.decode(response.responseText);
7391 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7401 Roo.form.Action.Load = function(form, options){
7402 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7403 this.reader = this.form.reader;
7406 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7411 Roo.Ajax.request(Roo.apply(
7412 this.createCallback(), {
7413 method:this.getMethod(),
7414 url:this.getUrl(false),
7415 params:this.getParams()
7419 success : function(response){
7421 var result = this.processResponse(response);
7422 if(result === true || !result.success || !result.data){
7423 this.failureType = Roo.form.Action.LOAD_FAILURE;
7424 this.form.afterAction(this, false);
7427 this.form.clearInvalid();
7428 this.form.setValues(result.data);
7429 this.form.afterAction(this, true);
7432 handleResponse : function(response){
7433 if(this.form.reader){
7434 var rs = this.form.reader.read(response);
7435 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7437 success : rs.success,
7441 return Roo.decode(response.responseText);
7445 Roo.form.Action.ACTION_TYPES = {
7446 'load' : Roo.form.Action.Load,
7447 'submit' : Roo.form.Action.Submit
7456 * @class Roo.bootstrap.Form
7457 * @extends Roo.bootstrap.Component
7458 * Bootstrap Form class
7459 * @cfg {String} method GET | POST (default POST)
7460 * @cfg {String} labelAlign top | left (default top)
7461 * @cfg {String} align left | right - for navbars
7462 * @cfg {Boolean} loadMask load mask when submit (default true)
7467 * @param {Object} config The config object
7471 Roo.bootstrap.Form = function(config){
7472 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7474 Roo.bootstrap.Form.popover.apply();
7478 * @event clientvalidation
7479 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7480 * @param {Form} this
7481 * @param {Boolean} valid true if the form has passed client-side validation
7483 clientvalidation: true,
7485 * @event beforeaction
7486 * Fires before any action is performed. Return false to cancel the action.
7487 * @param {Form} this
7488 * @param {Action} action The action to be performed
7492 * @event actionfailed
7493 * Fires when an action fails.
7494 * @param {Form} this
7495 * @param {Action} action The action that failed
7497 actionfailed : true,
7499 * @event actioncomplete
7500 * Fires when an action is completed.
7501 * @param {Form} this
7502 * @param {Action} action The action that completed
7504 actioncomplete : true
7509 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7512 * @cfg {String} method
7513 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7518 * The URL to use for form actions if one isn't supplied in the action options.
7521 * @cfg {Boolean} fileUpload
7522 * Set to true if this form is a file upload.
7526 * @cfg {Object} baseParams
7527 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7531 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7535 * @cfg {Sting} align (left|right) for navbar forms
7540 activeAction : null,
7543 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7544 * element by passing it or its id or mask the form itself by passing in true.
7547 waitMsgTarget : false,
7552 * @cfg {Boolean} errorMask (true|false) default false
7556 getAutoCreate : function(){
7560 method : this.method || 'POST',
7561 id : this.id || Roo.id(),
7564 if (this.parent().xtype.match(/^Nav/)) {
7565 cfg.cls = 'navbar-form navbar-' + this.align;
7569 if (this.labelAlign == 'left' ) {
7570 cfg.cls += ' form-horizontal';
7576 initEvents : function()
7578 this.el.on('submit', this.onSubmit, this);
7579 // this was added as random key presses on the form where triggering form submit.
7580 this.el.on('keypress', function(e) {
7581 if (e.getCharCode() != 13) {
7584 // we might need to allow it for textareas.. and some other items.
7585 // check e.getTarget().
7587 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7591 Roo.log("keypress blocked");
7599 onSubmit : function(e){
7604 * Returns true if client-side validation on the form is successful.
7607 isValid : function(){
7608 var items = this.getItems();
7612 items.each(function(f){
7619 if(!target && f.el.isVisible(true)){
7625 if(this.errorMask && !valid){
7626 Roo.bootstrap.Form.popover.mask(this, target);
7633 * Returns true if any fields in this form have changed since their original load.
7636 isDirty : function(){
7638 var items = this.getItems();
7639 items.each(function(f){
7649 * Performs a predefined action (submit or load) or custom actions you define on this form.
7650 * @param {String} actionName The name of the action type
7651 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7652 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7653 * accept other config options):
7655 Property Type Description
7656 ---------------- --------------- ----------------------------------------------------------------------------------
7657 url String The url for the action (defaults to the form's url)
7658 method String The form method to use (defaults to the form's method, or POST if not defined)
7659 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7660 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7661 validate the form on the client (defaults to false)
7663 * @return {BasicForm} this
7665 doAction : function(action, options){
7666 if(typeof action == 'string'){
7667 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7669 if(this.fireEvent('beforeaction', this, action) !== false){
7670 this.beforeAction(action);
7671 action.run.defer(100, action);
7677 beforeAction : function(action){
7678 var o = action.options;
7681 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7683 // not really supported yet.. ??
7685 //if(this.waitMsgTarget === true){
7686 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7687 //}else if(this.waitMsgTarget){
7688 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7689 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7691 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7697 afterAction : function(action, success){
7698 this.activeAction = null;
7699 var o = action.options;
7701 //if(this.waitMsgTarget === true){
7703 //}else if(this.waitMsgTarget){
7704 // this.waitMsgTarget.unmask();
7706 // Roo.MessageBox.updateProgress(1);
7707 // Roo.MessageBox.hide();
7714 Roo.callback(o.success, o.scope, [this, action]);
7715 this.fireEvent('actioncomplete', this, action);
7719 // failure condition..
7720 // we have a scenario where updates need confirming.
7721 // eg. if a locking scenario exists..
7722 // we look for { errors : { needs_confirm : true }} in the response.
7724 (typeof(action.result) != 'undefined') &&
7725 (typeof(action.result.errors) != 'undefined') &&
7726 (typeof(action.result.errors.needs_confirm) != 'undefined')
7729 Roo.log("not supported yet");
7732 Roo.MessageBox.confirm(
7733 "Change requires confirmation",
7734 action.result.errorMsg,
7739 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7749 Roo.callback(o.failure, o.scope, [this, action]);
7750 // show an error message if no failed handler is set..
7751 if (!this.hasListener('actionfailed')) {
7752 Roo.log("need to add dialog support");
7754 Roo.MessageBox.alert("Error",
7755 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7756 action.result.errorMsg :
7757 "Saving Failed, please check your entries or try again"
7762 this.fireEvent('actionfailed', this, action);
7767 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7768 * @param {String} id The value to search for
7771 findField : function(id){
7772 var items = this.getItems();
7773 var field = items.get(id);
7775 items.each(function(f){
7776 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7783 return field || null;
7786 * Mark fields in this form invalid in bulk.
7787 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7788 * @return {BasicForm} this
7790 markInvalid : function(errors){
7791 if(errors instanceof Array){
7792 for(var i = 0, len = errors.length; i < len; i++){
7793 var fieldError = errors[i];
7794 var f = this.findField(fieldError.id);
7796 f.markInvalid(fieldError.msg);
7802 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7803 field.markInvalid(errors[id]);
7807 //Roo.each(this.childForms || [], function (f) {
7808 // f.markInvalid(errors);
7815 * Set values for fields in this form in bulk.
7816 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7817 * @return {BasicForm} this
7819 setValues : function(values){
7820 if(values instanceof Array){ // array of objects
7821 for(var i = 0, len = values.length; i < len; i++){
7823 var f = this.findField(v.id);
7825 f.setValue(v.value);
7826 if(this.trackResetOnLoad){
7827 f.originalValue = f.getValue();
7831 }else{ // object hash
7834 if(typeof values[id] != 'function' && (field = this.findField(id))){
7836 if (field.setFromData &&
7838 field.displayField &&
7839 // combos' with local stores can
7840 // be queried via setValue()
7841 // to set their value..
7842 (field.store && !field.store.isLocal)
7846 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7847 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7848 field.setFromData(sd);
7851 field.setValue(values[id]);
7855 if(this.trackResetOnLoad){
7856 field.originalValue = field.getValue();
7862 //Roo.each(this.childForms || [], function (f) {
7863 // f.setValues(values);
7870 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7871 * they are returned as an array.
7872 * @param {Boolean} asString
7875 getValues : function(asString){
7876 //if (this.childForms) {
7877 // copy values from the child forms
7878 // Roo.each(this.childForms, function (f) {
7879 // this.setValues(f.getValues());
7885 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7886 if(asString === true){
7889 return Roo.urlDecode(fs);
7893 * Returns the fields in this form as an object with key/value pairs.
7894 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7897 getFieldValues : function(with_hidden)
7899 var items = this.getItems();
7901 items.each(function(f){
7905 var v = f.getValue();
7906 if (f.inputType =='radio') {
7907 if (typeof(ret[f.getName()]) == 'undefined') {
7908 ret[f.getName()] = ''; // empty..
7911 if (!f.el.dom.checked) {
7919 // not sure if this supported any more..
7920 if ((typeof(v) == 'object') && f.getRawValue) {
7921 v = f.getRawValue() ; // dates..
7923 // combo boxes where name != hiddenName...
7924 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7925 ret[f.name] = f.getRawValue();
7927 ret[f.getName()] = v;
7934 * Clears all invalid messages in this form.
7935 * @return {BasicForm} this
7937 clearInvalid : function(){
7938 var items = this.getItems();
7940 items.each(function(f){
7951 * @return {BasicForm} this
7954 var items = this.getItems();
7955 items.each(function(f){
7959 Roo.each(this.childForms || [], function (f) {
7966 getItems : function()
7968 var r=new Roo.util.MixedCollection(false, function(o){
7969 return o.id || (o.id = Roo.id());
7971 var iter = function(el) {
7978 Roo.each(el.items,function(e) {
7995 Roo.apply(Roo.bootstrap.Form, {
8022 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8023 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8024 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8025 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8028 this.maskEl.top.enableDisplayMode("block");
8029 this.maskEl.left.enableDisplayMode("block");
8030 this.maskEl.bottom.enableDisplayMode("block");
8031 this.maskEl.right.enableDisplayMode("block");
8033 this.toolTip = new Roo.bootstrap.Tooltip({
8034 cls : 'roo-form-error-popover',
8036 'left' : ['r-l', [-2,0], 'right'],
8037 'right' : ['l-r', [2,0], 'left'],
8038 'bottom' : ['tl-bl', [0,2], 'top'],
8039 'top' : [ 'bl-tl', [0,-2], 'bottom']
8043 this.toolTip.render(Roo.get(document.body));
8045 this.toolTip.el.enableDisplayMode("block");
8047 Roo.get(document.body).on('click', function(){
8051 this.isApplied = true
8054 mask : function(form, target)
8058 this.target = target;
8060 if(!this.form.errorMask || !target.el){
8064 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8066 var scrolled = scrollable.getScroll();
8068 var ot = this.target.el.calcOffsetsTo(scrollable);
8070 scrollTo = ot[1] - 100;
8072 scrollable.scrollTo('top', scrollTo);
8074 var box = this.target.el.getBox();
8076 var zIndex = Roo.bootstrap.Modal.zIndex++;
8078 this.maskEl.top.setStyle('position', 'fixed');
8079 this.maskEl.top.setStyle('z-index', zIndex);
8080 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8081 this.maskEl.top.setXY([0, 0]);
8082 this.maskEl.top.show();
8084 this.maskEl.left.setStyle('position', 'fixed');
8085 this.maskEl.left.setStyle('z-index', zIndex);
8086 this.maskEl.left.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8087 this.maskEl.left.setXY([box.right + this.padding, box.y - this.padding]);
8088 this.maskEl.left.show();
8090 this.maskEl.bottom.setStyle('position', 'fixed');
8091 this.maskEl.bottom.setStyle('z-index', zIndex);
8092 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8093 this.maskEl.bottom.setXY([0, box.bottom + this.padding]);
8094 this.maskEl.bottom.show();
8096 this.maskEl.right.setStyle('position', 'fixed');
8097 this.maskEl.right.setStyle('z-index', zIndex);
8098 this.maskEl.right.setSize(box.x - this.padding, box.height + this.padding * 2);
8099 this.maskEl.right.setXY([0, box.y - this.padding]);
8100 this.maskEl.right.show();
8103 this.toolTip.bindEl = this.target.el;
8105 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8107 var tip = this.target.blankText;
8109 if(this.target.getValue() !== '' && this.target.regexText.length){
8110 tip = this.target.regexText;
8113 this.toolTip.show(tip);
8115 this.intervalID = window.setInterval(function() {
8116 Roo.bootstrap.Form.popover.unmask();
8119 window.onwheel = function(){ return false;};
8121 (function(){ this.isMasked = true; }).defer(500, this);
8129 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8133 this.maskEl.top.setStyle('position', 'absolute');
8134 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8135 this.maskEl.top.hide();
8137 this.maskEl.left.setStyle('position', 'absolute');
8138 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8139 this.maskEl.left.hide();
8141 this.maskEl.bottom.setStyle('position', 'absolute');
8142 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8143 this.maskEl.bottom.hide();
8145 this.maskEl.right.setStyle('position', 'absolute');
8146 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8147 this.maskEl.right.hide();
8149 this.toolTip.hide();
8151 this.toolTip.el.hide();
8153 window.onwheel = function(){ return true;};
8155 if(this.intervalID){
8156 window.clearInterval(this.intervalID);
8157 this.intervalID = false;
8160 this.isMasked = false;
8170 * Ext JS Library 1.1.1
8171 * Copyright(c) 2006-2007, Ext JS, LLC.
8173 * Originally Released Under LGPL - original licence link has changed is not relivant.
8176 * <script type="text/javascript">
8179 * @class Roo.form.VTypes
8180 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8183 Roo.form.VTypes = function(){
8184 // closure these in so they are only created once.
8185 var alpha = /^[a-zA-Z_]+$/;
8186 var alphanum = /^[a-zA-Z0-9_]+$/;
8187 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8188 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8190 // All these messages and functions are configurable
8193 * The function used to validate email addresses
8194 * @param {String} value The email address
8196 'email' : function(v){
8197 return email.test(v);
8200 * The error text to display when the email validation function returns false
8203 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8205 * The keystroke filter mask to be applied on email input
8208 'emailMask' : /[a-z0-9_\.\-@]/i,
8211 * The function used to validate URLs
8212 * @param {String} value The URL
8214 'url' : function(v){
8218 * The error text to display when the url validation function returns false
8221 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8224 * The function used to validate alpha values
8225 * @param {String} value The value
8227 'alpha' : function(v){
8228 return alpha.test(v);
8231 * The error text to display when the alpha validation function returns false
8234 'alphaText' : 'This field should only contain letters and _',
8236 * The keystroke filter mask to be applied on alpha input
8239 'alphaMask' : /[a-z_]/i,
8242 * The function used to validate alphanumeric values
8243 * @param {String} value The value
8245 'alphanum' : function(v){
8246 return alphanum.test(v);
8249 * The error text to display when the alphanumeric validation function returns false
8252 'alphanumText' : 'This field should only contain letters, numbers and _',
8254 * The keystroke filter mask to be applied on alphanumeric input
8257 'alphanumMask' : /[a-z0-9_]/i
8267 * @class Roo.bootstrap.Input
8268 * @extends Roo.bootstrap.Component
8269 * Bootstrap Input class
8270 * @cfg {Boolean} disabled is it disabled
8271 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8272 * @cfg {String} name name of the input
8273 * @cfg {string} fieldLabel - the label associated
8274 * @cfg {string} placeholder - placeholder to put in text.
8275 * @cfg {string} before - input group add on before
8276 * @cfg {string} after - input group add on after
8277 * @cfg {string} size - (lg|sm) or leave empty..
8278 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8279 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8280 * @cfg {Number} md colspan out of 12 for computer-sized screens
8281 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8282 * @cfg {string} value default value of the input
8283 * @cfg {Number} labelWidth set the width of label
8284 * @cfg {Number} labellg set the width of label (1-12)
8285 * @cfg {Number} labelmd set the width of label (1-12)
8286 * @cfg {Number} labelsm set the width of label (1-12)
8287 * @cfg {Number} labelxs set the width of label (1-12)
8288 * @cfg {String} labelAlign (top|left)
8289 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8290 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8291 * @cfg {String} indicatorpos (left|right) default left
8293 * @cfg {String} align (left|center|right) Default left
8294 * @cfg {Boolean} forceFeedback (true|false) Default false
8300 * Create a new Input
8301 * @param {Object} config The config object
8304 Roo.bootstrap.Input = function(config){
8306 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8311 * Fires when this field receives input focus.
8312 * @param {Roo.form.Field} this
8317 * Fires when this field loses input focus.
8318 * @param {Roo.form.Field} this
8323 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8324 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8325 * @param {Roo.form.Field} this
8326 * @param {Roo.EventObject} e The event object
8331 * Fires just before the field blurs if the field value has changed.
8332 * @param {Roo.form.Field} this
8333 * @param {Mixed} newValue The new value
8334 * @param {Mixed} oldValue The original value
8339 * Fires after the field has been marked as invalid.
8340 * @param {Roo.form.Field} this
8341 * @param {String} msg The validation message
8346 * Fires after the field has been validated with no errors.
8347 * @param {Roo.form.Field} this
8352 * Fires after the key up
8353 * @param {Roo.form.Field} this
8354 * @param {Roo.EventObject} e The event Object
8360 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8362 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8363 automatic validation (defaults to "keyup").
8365 validationEvent : "keyup",
8367 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8369 validateOnBlur : true,
8371 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8373 validationDelay : 250,
8375 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8377 focusClass : "x-form-focus", // not needed???
8381 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8383 invalidClass : "has-warning",
8386 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8388 validClass : "has-success",
8391 * @cfg {Boolean} hasFeedback (true|false) default true
8396 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8398 invalidFeedbackClass : "glyphicon-warning-sign",
8401 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8403 validFeedbackClass : "glyphicon-ok",
8406 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8408 selectOnFocus : false,
8411 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8415 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8420 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8422 disableKeyFilter : false,
8425 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8429 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8433 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8435 blankText : "Please complete this mandatory field",
8438 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8442 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8444 maxLength : Number.MAX_VALUE,
8446 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8448 minLengthText : "The minimum length for this field is {0}",
8450 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8452 maxLengthText : "The maximum length for this field is {0}",
8456 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8457 * If available, this function will be called only after the basic validators all return true, and will be passed the
8458 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8462 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8463 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8464 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8468 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8472 autocomplete: false,
8491 formatedValue : false,
8492 forceFeedback : false,
8494 indicatorpos : 'left',
8501 parentLabelAlign : function()
8504 while (parent.parent()) {
8505 parent = parent.parent();
8506 if (typeof(parent.labelAlign) !='undefined') {
8507 return parent.labelAlign;
8514 getAutoCreate : function()
8516 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8522 if(this.inputType != 'hidden'){
8523 cfg.cls = 'form-group' //input-group
8529 type : this.inputType,
8531 cls : 'form-control',
8532 placeholder : this.placeholder || '',
8533 autocomplete : this.autocomplete || 'new-password'
8537 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8540 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8541 input.maxLength = this.maxLength;
8544 if (this.disabled) {
8545 input.disabled=true;
8548 if (this.readOnly) {
8549 input.readonly=true;
8553 input.name = this.name;
8557 input.cls += ' input-' + this.size;
8561 ['xs','sm','md','lg'].map(function(size){
8562 if (settings[size]) {
8563 cfg.cls += ' col-' + size + '-' + settings[size];
8567 var inputblock = input;
8571 cls: 'glyphicon form-control-feedback'
8574 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8577 cls : 'has-feedback',
8585 if (this.before || this.after) {
8588 cls : 'input-group',
8592 if (this.before && typeof(this.before) == 'string') {
8594 inputblock.cn.push({
8596 cls : 'roo-input-before input-group-addon',
8600 if (this.before && typeof(this.before) == 'object') {
8601 this.before = Roo.factory(this.before);
8603 inputblock.cn.push({
8605 cls : 'roo-input-before input-group-' +
8606 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8610 inputblock.cn.push(input);
8612 if (this.after && typeof(this.after) == 'string') {
8613 inputblock.cn.push({
8615 cls : 'roo-input-after input-group-addon',
8619 if (this.after && typeof(this.after) == 'object') {
8620 this.after = Roo.factory(this.after);
8622 inputblock.cn.push({
8624 cls : 'roo-input-after input-group-' +
8625 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8629 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8630 inputblock.cls += ' has-feedback';
8631 inputblock.cn.push(feedback);
8635 if (align ==='left' && this.fieldLabel.length) {
8637 cfg.cls += ' roo-form-group-label-left';
8642 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8643 tooltip : 'This field is required'
8648 cls : 'control-label',
8649 html : this.fieldLabel
8660 var labelCfg = cfg.cn[1];
8661 var contentCfg = cfg.cn[2];
8663 if(this.indicatorpos == 'right'){
8668 cls : 'control-label',
8669 html : this.fieldLabel
8674 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8675 tooltip : 'This field is required'
8686 labelCfg = cfg.cn[0];
8687 contentCfg = cfg.cn[2];
8691 if(this.labelWidth > 12){
8692 labelCfg.style = "width: " + this.labelWidth + 'px';
8695 if(this.labelWidth < 13 && this.labelmd == 0){
8696 this.labelmd = this.labelWidth;
8699 if(this.labellg > 0){
8700 labelCfg.cls += ' col-lg-' + this.labellg;
8701 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8704 if(this.labelmd > 0){
8705 labelCfg.cls += ' col-md-' + this.labelmd;
8706 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8709 if(this.labelsm > 0){
8710 labelCfg.cls += ' col-sm-' + this.labelsm;
8711 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8714 if(this.labelxs > 0){
8715 labelCfg.cls += ' col-xs-' + this.labelxs;
8716 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8720 } else if ( this.fieldLabel.length) {
8725 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8726 tooltip : 'This field is required'
8730 //cls : 'input-group-addon',
8731 html : this.fieldLabel
8739 if(this.indicatorpos == 'right'){
8744 //cls : 'input-group-addon',
8745 html : this.fieldLabel
8750 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8751 tooltip : 'This field is required'
8771 if (this.parentType === 'Navbar' && this.parent().bar) {
8772 cfg.cls += ' navbar-form';
8775 if (this.parentType === 'NavGroup') {
8776 cfg.cls += ' navbar-form';
8784 * return the real input element.
8786 inputEl: function ()
8788 return this.el.select('input.form-control',true).first();
8791 tooltipEl : function()
8793 return this.inputEl();
8796 indicatorEl : function()
8798 var indicator = this.el.select('i.roo-required-indicator',true).first();
8808 setDisabled : function(v)
8810 var i = this.inputEl().dom;
8812 i.removeAttribute('disabled');
8816 i.setAttribute('disabled','true');
8818 initEvents : function()
8821 this.inputEl().on("keydown" , this.fireKey, this);
8822 this.inputEl().on("focus", this.onFocus, this);
8823 this.inputEl().on("blur", this.onBlur, this);
8825 this.inputEl().relayEvent('keyup', this);
8827 this.indicator = this.indicatorEl();
8830 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8831 this.indicator.hide();
8834 // reference to original value for reset
8835 this.originalValue = this.getValue();
8836 //Roo.form.TextField.superclass.initEvents.call(this);
8837 if(this.validationEvent == 'keyup'){
8838 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8839 this.inputEl().on('keyup', this.filterValidation, this);
8841 else if(this.validationEvent !== false){
8842 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8845 if(this.selectOnFocus){
8846 this.on("focus", this.preFocus, this);
8849 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8850 this.inputEl().on("keypress", this.filterKeys, this);
8852 this.inputEl().relayEvent('keypress', this);
8855 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8856 this.el.on("click", this.autoSize, this);
8859 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8860 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8863 if (typeof(this.before) == 'object') {
8864 this.before.render(this.el.select('.roo-input-before',true).first());
8866 if (typeof(this.after) == 'object') {
8867 this.after.render(this.el.select('.roo-input-after',true).first());
8872 filterValidation : function(e){
8873 if(!e.isNavKeyPress()){
8874 this.validationTask.delay(this.validationDelay);
8878 * Validates the field value
8879 * @return {Boolean} True if the value is valid, else false
8881 validate : function(){
8882 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8883 if(this.disabled || this.validateValue(this.getRawValue())){
8894 * Validates a value according to the field's validation rules and marks the field as invalid
8895 * if the validation fails
8896 * @param {Mixed} value The value to validate
8897 * @return {Boolean} True if the value is valid, else false
8899 validateValue : function(value){
8900 if(value.length < 1) { // if it's blank
8901 if(this.allowBlank){
8907 if(value.length < this.minLength){
8910 if(value.length > this.maxLength){
8914 var vt = Roo.form.VTypes;
8915 if(!vt[this.vtype](value, this)){
8919 if(typeof this.validator == "function"){
8920 var msg = this.validator(value);
8926 if(this.regex && !this.regex.test(value)){
8936 fireKey : function(e){
8937 //Roo.log('field ' + e.getKey());
8938 if(e.isNavKeyPress()){
8939 this.fireEvent("specialkey", this, e);
8942 focus : function (selectText){
8944 this.inputEl().focus();
8945 if(selectText === true){
8946 this.inputEl().dom.select();
8952 onFocus : function(){
8953 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8954 // this.el.addClass(this.focusClass);
8957 this.hasFocus = true;
8958 this.startValue = this.getValue();
8959 this.fireEvent("focus", this);
8963 beforeBlur : Roo.emptyFn,
8967 onBlur : function(){
8969 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8970 //this.el.removeClass(this.focusClass);
8972 this.hasFocus = false;
8973 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8976 var v = this.getValue();
8977 if(String(v) !== String(this.startValue)){
8978 this.fireEvent('change', this, v, this.startValue);
8980 this.fireEvent("blur", this);
8984 * Resets the current field value to the originally loaded value and clears any validation messages
8987 this.setValue(this.originalValue);
8991 * Returns the name of the field
8992 * @return {Mixed} name The name field
8994 getName: function(){
8998 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8999 * @return {Mixed} value The field value
9001 getValue : function(){
9003 var v = this.inputEl().getValue();
9008 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9009 * @return {Mixed} value The field value
9011 getRawValue : function(){
9012 var v = this.inputEl().getValue();
9018 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9019 * @param {Mixed} value The value to set
9021 setRawValue : function(v){
9022 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9025 selectText : function(start, end){
9026 var v = this.getRawValue();
9028 start = start === undefined ? 0 : start;
9029 end = end === undefined ? v.length : end;
9030 var d = this.inputEl().dom;
9031 if(d.setSelectionRange){
9032 d.setSelectionRange(start, end);
9033 }else if(d.createTextRange){
9034 var range = d.createTextRange();
9035 range.moveStart("character", start);
9036 range.moveEnd("character", v.length-end);
9043 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9044 * @param {Mixed} value The value to set
9046 setValue : function(v){
9049 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9055 processValue : function(value){
9056 if(this.stripCharsRe){
9057 var newValue = value.replace(this.stripCharsRe, '');
9058 if(newValue !== value){
9059 this.setRawValue(newValue);
9066 preFocus : function(){
9068 if(this.selectOnFocus){
9069 this.inputEl().dom.select();
9072 filterKeys : function(e){
9074 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9077 var c = e.getCharCode(), cc = String.fromCharCode(c);
9078 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9081 if(!this.maskRe.test(cc)){
9086 * Clear any invalid styles/messages for this field
9088 clearInvalid : function(){
9090 if(!this.el || this.preventMark){ // not rendered
9096 this.indicator.hide();
9100 this.el.removeClass(this.invalidClass);
9102 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9104 var feedback = this.el.select('.form-control-feedback', true).first();
9107 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9112 this.fireEvent('valid', this);
9116 * Mark this field as valid
9118 markValid : function()
9120 if(!this.el || this.preventMark){ // not rendered...
9124 this.el.removeClass([this.invalidClass, this.validClass]);
9126 var feedback = this.el.select('.form-control-feedback', true).first();
9129 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9136 if(this.allowBlank && !this.getRawValue().length){
9141 this.indicator.hide();
9144 this.el.addClass(this.validClass);
9146 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9148 var feedback = this.el.select('.form-control-feedback', true).first();
9151 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9152 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9157 this.fireEvent('valid', this);
9161 * Mark this field as invalid
9162 * @param {String} msg The validation message
9164 markInvalid : function(msg)
9166 if(!this.el || this.preventMark){ // not rendered
9170 this.el.removeClass([this.invalidClass, this.validClass]);
9172 var feedback = this.el.select('.form-control-feedback', true).first();
9175 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9182 if(this.allowBlank && !this.getRawValue().length){
9187 this.indicator.show();
9190 this.el.addClass(this.invalidClass);
9192 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9194 var feedback = this.el.select('.form-control-feedback', true).first();
9197 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9199 if(this.getValue().length || this.forceFeedback){
9200 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9207 this.fireEvent('invalid', this, msg);
9210 SafariOnKeyDown : function(event)
9212 // this is a workaround for a password hang bug on chrome/ webkit.
9213 if (this.inputEl().dom.type != 'password') {
9217 var isSelectAll = false;
9219 if(this.inputEl().dom.selectionEnd > 0){
9220 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9222 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9223 event.preventDefault();
9228 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9230 event.preventDefault();
9231 // this is very hacky as keydown always get's upper case.
9233 var cc = String.fromCharCode(event.getCharCode());
9234 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9238 adjustWidth : function(tag, w){
9239 tag = tag.toLowerCase();
9240 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9241 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9245 if(tag == 'textarea'){
9248 }else if(Roo.isOpera){
9252 if(tag == 'textarea'){
9271 * @class Roo.bootstrap.TextArea
9272 * @extends Roo.bootstrap.Input
9273 * Bootstrap TextArea class
9274 * @cfg {Number} cols Specifies the visible width of a text area
9275 * @cfg {Number} rows Specifies the visible number of lines in a text area
9276 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9277 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9278 * @cfg {string} html text
9281 * Create a new TextArea
9282 * @param {Object} config The config object
9285 Roo.bootstrap.TextArea = function(config){
9286 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9290 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9300 getAutoCreate : function(){
9302 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9313 value : this.value || '',
9314 html: this.html || '',
9315 cls : 'form-control',
9316 placeholder : this.placeholder || ''
9320 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9321 input.maxLength = this.maxLength;
9325 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9329 input.cols = this.cols;
9332 if (this.readOnly) {
9333 input.readonly = true;
9337 input.name = this.name;
9341 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9345 ['xs','sm','md','lg'].map(function(size){
9346 if (settings[size]) {
9347 cfg.cls += ' col-' + size + '-' + settings[size];
9351 var inputblock = input;
9353 if(this.hasFeedback && !this.allowBlank){
9357 cls: 'glyphicon form-control-feedback'
9361 cls : 'has-feedback',
9370 if (this.before || this.after) {
9373 cls : 'input-group',
9377 inputblock.cn.push({
9379 cls : 'input-group-addon',
9384 inputblock.cn.push(input);
9386 if(this.hasFeedback && !this.allowBlank){
9387 inputblock.cls += ' has-feedback';
9388 inputblock.cn.push(feedback);
9392 inputblock.cn.push({
9394 cls : 'input-group-addon',
9401 if (align ==='left' && this.fieldLabel.length) {
9406 cls : 'control-label',
9407 html : this.fieldLabel
9418 if(this.labelWidth > 12){
9419 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9422 if(this.labelWidth < 13 && this.labelmd == 0){
9423 this.labelmd = this.labelWidth;
9426 if(this.labellg > 0){
9427 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9428 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9431 if(this.labelmd > 0){
9432 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9433 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9436 if(this.labelsm > 0){
9437 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9438 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9441 if(this.labelxs > 0){
9442 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9443 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9446 } else if ( this.fieldLabel.length) {
9451 //cls : 'input-group-addon',
9452 html : this.fieldLabel
9470 if (this.disabled) {
9471 input.disabled=true;
9478 * return the real textarea element.
9480 inputEl: function ()
9482 return this.el.select('textarea.form-control',true).first();
9486 * Clear any invalid styles/messages for this field
9488 clearInvalid : function()
9491 if(!this.el || this.preventMark){ // not rendered
9495 var label = this.el.select('label', true).first();
9496 var icon = this.el.select('i.fa-star', true).first();
9502 this.el.removeClass(this.invalidClass);
9504 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9506 var feedback = this.el.select('.form-control-feedback', true).first();
9509 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9514 this.fireEvent('valid', this);
9518 * Mark this field as valid
9520 markValid : function()
9522 if(!this.el || this.preventMark){ // not rendered
9526 this.el.removeClass([this.invalidClass, this.validClass]);
9528 var feedback = this.el.select('.form-control-feedback', true).first();
9531 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9534 if(this.disabled || this.allowBlank){
9538 var label = this.el.select('label', true).first();
9539 var icon = this.el.select('i.fa-star', true).first();
9545 this.el.addClass(this.validClass);
9547 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9549 var feedback = this.el.select('.form-control-feedback', true).first();
9552 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9553 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9558 this.fireEvent('valid', this);
9562 * Mark this field as invalid
9563 * @param {String} msg The validation message
9565 markInvalid : function(msg)
9567 if(!this.el || this.preventMark){ // not rendered
9571 this.el.removeClass([this.invalidClass, this.validClass]);
9573 var feedback = this.el.select('.form-control-feedback', true).first();
9576 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9579 if(this.disabled || this.allowBlank){
9583 var label = this.el.select('label', true).first();
9584 var icon = this.el.select('i.fa-star', true).first();
9586 if(!this.getValue().length && label && !icon){
9587 this.el.createChild({
9589 cls : 'text-danger fa fa-lg fa-star',
9590 tooltip : 'This field is required',
9591 style : 'margin-right:5px;'
9595 this.el.addClass(this.invalidClass);
9597 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9599 var feedback = this.el.select('.form-control-feedback', true).first();
9602 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9604 if(this.getValue().length || this.forceFeedback){
9605 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9612 this.fireEvent('invalid', this, msg);
9620 * trigger field - base class for combo..
9625 * @class Roo.bootstrap.TriggerField
9626 * @extends Roo.bootstrap.Input
9627 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9628 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9629 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9630 * for which you can provide a custom implementation. For example:
9632 var trigger = new Roo.bootstrap.TriggerField();
9633 trigger.onTriggerClick = myTriggerFn;
9634 trigger.applyTo('my-field');
9637 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9638 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9639 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9640 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9641 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9644 * Create a new TriggerField.
9645 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9646 * to the base TextField)
9648 Roo.bootstrap.TriggerField = function(config){
9649 this.mimicing = false;
9650 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9653 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9655 * @cfg {String} triggerClass A CSS class to apply to the trigger
9658 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9663 * @cfg {Boolean} removable (true|false) special filter default false
9667 /** @cfg {Boolean} grow @hide */
9668 /** @cfg {Number} growMin @hide */
9669 /** @cfg {Number} growMax @hide */
9675 autoSize: Roo.emptyFn,
9682 actionMode : 'wrap',
9687 getAutoCreate : function(){
9689 var align = this.labelAlign || this.parentLabelAlign();
9694 cls: 'form-group' //input-group
9701 type : this.inputType,
9702 cls : 'form-control',
9703 autocomplete: 'new-password',
9704 placeholder : this.placeholder || ''
9708 input.name = this.name;
9711 input.cls += ' input-' + this.size;
9714 if (this.disabled) {
9715 input.disabled=true;
9718 var inputblock = input;
9720 if(this.hasFeedback && !this.allowBlank){
9724 cls: 'glyphicon form-control-feedback'
9727 if(this.removable && !this.editable && !this.tickable){
9729 cls : 'has-feedback',
9735 cls : 'roo-combo-removable-btn close'
9742 cls : 'has-feedback',
9751 if(this.removable && !this.editable && !this.tickable){
9753 cls : 'roo-removable',
9759 cls : 'roo-combo-removable-btn close'
9766 if (this.before || this.after) {
9769 cls : 'input-group',
9773 inputblock.cn.push({
9775 cls : 'input-group-addon',
9780 inputblock.cn.push(input);
9782 if(this.hasFeedback && !this.allowBlank){
9783 inputblock.cls += ' has-feedback';
9784 inputblock.cn.push(feedback);
9788 inputblock.cn.push({
9790 cls : 'input-group-addon',
9803 cls: 'form-hidden-field'
9817 cls: 'form-hidden-field'
9821 cls: 'roo-select2-choices',
9825 cls: 'roo-select2-search-field',
9838 cls: 'roo-select2-container input-group',
9843 // cls: 'typeahead typeahead-long dropdown-menu',
9844 // style: 'display:none'
9849 if(!this.multiple && this.showToggleBtn){
9855 if (this.caret != false) {
9858 cls: 'fa fa-' + this.caret
9865 cls : 'input-group-addon btn dropdown-toggle',
9870 cls: 'combobox-clear',
9884 combobox.cls += ' roo-select2-container-multi';
9887 if (align ==='left' && this.fieldLabel.length) {
9889 cfg.cls += ' roo-form-group-label-left';
9894 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9895 tooltip : 'This field is required'
9900 cls : 'control-label',
9901 html : this.fieldLabel
9913 var labelCfg = cfg.cn[1];
9914 var contentCfg = cfg.cn[2];
9916 if(this.indicatorpos == 'right'){
9921 cls : 'control-label',
9925 html : this.fieldLabel
9929 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9930 tooltip : 'This field is required'
9943 labelCfg = cfg.cn[0];
9944 contentCfg = cfg.cn[1];
9947 if(this.labelWidth > 12){
9948 labelCfg.style = "width: " + this.labelWidth + 'px';
9951 if(this.labelWidth < 13 && this.labelmd == 0){
9952 this.labelmd = this.labelWidth;
9955 if(this.labellg > 0){
9956 labelCfg.cls += ' col-lg-' + this.labellg;
9957 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9960 if(this.labelmd > 0){
9961 labelCfg.cls += ' col-md-' + this.labelmd;
9962 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9965 if(this.labelsm > 0){
9966 labelCfg.cls += ' col-sm-' + this.labelsm;
9967 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9970 if(this.labelxs > 0){
9971 labelCfg.cls += ' col-xs-' + this.labelxs;
9972 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9975 } else if ( this.fieldLabel.length) {
9976 // Roo.log(" label");
9980 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9981 tooltip : 'This field is required'
9985 //cls : 'input-group-addon',
9986 html : this.fieldLabel
9994 if(this.indicatorpos == 'right'){
10002 html : this.fieldLabel
10006 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10007 tooltip : 'This field is required'
10020 // Roo.log(" no label && no align");
10027 ['xs','sm','md','lg'].map(function(size){
10028 if (settings[size]) {
10029 cfg.cls += ' col-' + size + '-' + settings[size];
10040 onResize : function(w, h){
10041 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10042 // if(typeof w == 'number'){
10043 // var x = w - this.trigger.getWidth();
10044 // this.inputEl().setWidth(this.adjustWidth('input', x));
10045 // this.trigger.setStyle('left', x+'px');
10050 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10053 getResizeEl : function(){
10054 return this.inputEl();
10058 getPositionEl : function(){
10059 return this.inputEl();
10063 alignErrorIcon : function(){
10064 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10068 initEvents : function(){
10072 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10073 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10074 if(!this.multiple && this.showToggleBtn){
10075 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10076 if(this.hideTrigger){
10077 this.trigger.setDisplayed(false);
10079 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10083 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10086 if(this.removable && !this.editable && !this.tickable){
10087 var close = this.closeTriggerEl();
10090 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10091 close.on('click', this.removeBtnClick, this, close);
10095 //this.trigger.addClassOnOver('x-form-trigger-over');
10096 //this.trigger.addClassOnClick('x-form-trigger-click');
10099 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10103 closeTriggerEl : function()
10105 var close = this.el.select('.roo-combo-removable-btn', true).first();
10106 return close ? close : false;
10109 removeBtnClick : function(e, h, el)
10111 e.preventDefault();
10113 if(this.fireEvent("remove", this) !== false){
10115 this.fireEvent("afterremove", this)
10119 createList : function()
10121 this.list = Roo.get(document.body).createChild({
10123 cls: 'typeahead typeahead-long dropdown-menu',
10124 style: 'display:none'
10127 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10132 initTrigger : function(){
10137 onDestroy : function(){
10139 this.trigger.removeAllListeners();
10140 // this.trigger.remove();
10143 // this.wrap.remove();
10145 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10149 onFocus : function(){
10150 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10152 if(!this.mimicing){
10153 this.wrap.addClass('x-trigger-wrap-focus');
10154 this.mimicing = true;
10155 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10156 if(this.monitorTab){
10157 this.el.on("keydown", this.checkTab, this);
10164 checkTab : function(e){
10165 if(e.getKey() == e.TAB){
10166 this.triggerBlur();
10171 onBlur : function(){
10176 mimicBlur : function(e, t){
10178 if(!this.wrap.contains(t) && this.validateBlur()){
10179 this.triggerBlur();
10185 triggerBlur : function(){
10186 this.mimicing = false;
10187 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10188 if(this.monitorTab){
10189 this.el.un("keydown", this.checkTab, this);
10191 //this.wrap.removeClass('x-trigger-wrap-focus');
10192 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10196 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10197 validateBlur : function(e, t){
10202 onDisable : function(){
10203 this.inputEl().dom.disabled = true;
10204 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10206 // this.wrap.addClass('x-item-disabled');
10211 onEnable : function(){
10212 this.inputEl().dom.disabled = false;
10213 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10215 // this.el.removeClass('x-item-disabled');
10220 onShow : function(){
10221 var ae = this.getActionEl();
10224 ae.dom.style.display = '';
10225 ae.dom.style.visibility = 'visible';
10231 onHide : function(){
10232 var ae = this.getActionEl();
10233 ae.dom.style.display = 'none';
10237 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10238 * by an implementing function.
10240 * @param {EventObject} e
10242 onTriggerClick : Roo.emptyFn
10246 * Ext JS Library 1.1.1
10247 * Copyright(c) 2006-2007, Ext JS, LLC.
10249 * Originally Released Under LGPL - original licence link has changed is not relivant.
10252 * <script type="text/javascript">
10257 * @class Roo.data.SortTypes
10259 * Defines the default sorting (casting?) comparison functions used when sorting data.
10261 Roo.data.SortTypes = {
10263 * Default sort that does nothing
10264 * @param {Mixed} s The value being converted
10265 * @return {Mixed} The comparison value
10267 none : function(s){
10272 * The regular expression used to strip tags
10276 stripTagsRE : /<\/?[^>]+>/gi,
10279 * Strips all HTML tags to sort on text only
10280 * @param {Mixed} s The value being converted
10281 * @return {String} The comparison value
10283 asText : function(s){
10284 return String(s).replace(this.stripTagsRE, "");
10288 * Strips all HTML tags to sort on text only - Case insensitive
10289 * @param {Mixed} s The value being converted
10290 * @return {String} The comparison value
10292 asUCText : function(s){
10293 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10297 * Case insensitive string
10298 * @param {Mixed} s The value being converted
10299 * @return {String} The comparison value
10301 asUCString : function(s) {
10302 return String(s).toUpperCase();
10307 * @param {Mixed} s The value being converted
10308 * @return {Number} The comparison value
10310 asDate : function(s) {
10314 if(s instanceof Date){
10315 return s.getTime();
10317 return Date.parse(String(s));
10322 * @param {Mixed} s The value being converted
10323 * @return {Float} The comparison value
10325 asFloat : function(s) {
10326 var val = parseFloat(String(s).replace(/,/g, ""));
10335 * @param {Mixed} s The value being converted
10336 * @return {Number} The comparison value
10338 asInt : function(s) {
10339 var val = parseInt(String(s).replace(/,/g, ""));
10347 * Ext JS Library 1.1.1
10348 * Copyright(c) 2006-2007, Ext JS, LLC.
10350 * Originally Released Under LGPL - original licence link has changed is not relivant.
10353 * <script type="text/javascript">
10357 * @class Roo.data.Record
10358 * Instances of this class encapsulate both record <em>definition</em> information, and record
10359 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10360 * to access Records cached in an {@link Roo.data.Store} object.<br>
10362 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10363 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10366 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10368 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10369 * {@link #create}. The parameters are the same.
10370 * @param {Array} data An associative Array of data values keyed by the field name.
10371 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10372 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10373 * not specified an integer id is generated.
10375 Roo.data.Record = function(data, id){
10376 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10381 * Generate a constructor for a specific record layout.
10382 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10383 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10384 * Each field definition object may contain the following properties: <ul>
10385 * <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,
10386 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10387 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10388 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10389 * is being used, then this is a string containing the javascript expression to reference the data relative to
10390 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10391 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10392 * this may be omitted.</p></li>
10393 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10394 * <ul><li>auto (Default, implies no conversion)</li>
10399 * <li>date</li></ul></p></li>
10400 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10401 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10402 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10403 * by the Reader into an object that will be stored in the Record. It is passed the
10404 * following parameters:<ul>
10405 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10407 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10409 * <br>usage:<br><pre><code>
10410 var TopicRecord = Roo.data.Record.create(
10411 {name: 'title', mapping: 'topic_title'},
10412 {name: 'author', mapping: 'username'},
10413 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10414 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10415 {name: 'lastPoster', mapping: 'user2'},
10416 {name: 'excerpt', mapping: 'post_text'}
10419 var myNewRecord = new TopicRecord({
10420 title: 'Do my job please',
10423 lastPost: new Date(),
10424 lastPoster: 'Animal',
10425 excerpt: 'No way dude!'
10427 myStore.add(myNewRecord);
10432 Roo.data.Record.create = function(o){
10433 var f = function(){
10434 f.superclass.constructor.apply(this, arguments);
10436 Roo.extend(f, Roo.data.Record);
10437 var p = f.prototype;
10438 p.fields = new Roo.util.MixedCollection(false, function(field){
10441 for(var i = 0, len = o.length; i < len; i++){
10442 p.fields.add(new Roo.data.Field(o[i]));
10444 f.getField = function(name){
10445 return p.fields.get(name);
10450 Roo.data.Record.AUTO_ID = 1000;
10451 Roo.data.Record.EDIT = 'edit';
10452 Roo.data.Record.REJECT = 'reject';
10453 Roo.data.Record.COMMIT = 'commit';
10455 Roo.data.Record.prototype = {
10457 * Readonly flag - true if this record has been modified.
10466 join : function(store){
10467 this.store = store;
10471 * Set the named field to the specified value.
10472 * @param {String} name The name of the field to set.
10473 * @param {Object} value The value to set the field to.
10475 set : function(name, value){
10476 if(this.data[name] == value){
10480 if(!this.modified){
10481 this.modified = {};
10483 if(typeof this.modified[name] == 'undefined'){
10484 this.modified[name] = this.data[name];
10486 this.data[name] = value;
10487 if(!this.editing && this.store){
10488 this.store.afterEdit(this);
10493 * Get the value of the named field.
10494 * @param {String} name The name of the field to get the value of.
10495 * @return {Object} The value of the field.
10497 get : function(name){
10498 return this.data[name];
10502 beginEdit : function(){
10503 this.editing = true;
10504 this.modified = {};
10508 cancelEdit : function(){
10509 this.editing = false;
10510 delete this.modified;
10514 endEdit : function(){
10515 this.editing = false;
10516 if(this.dirty && this.store){
10517 this.store.afterEdit(this);
10522 * Usually called by the {@link Roo.data.Store} which owns the Record.
10523 * Rejects all changes made to the Record since either creation, or the last commit operation.
10524 * Modified fields are reverted to their original values.
10526 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10527 * of reject operations.
10529 reject : function(){
10530 var m = this.modified;
10532 if(typeof m[n] != "function"){
10533 this.data[n] = m[n];
10536 this.dirty = false;
10537 delete this.modified;
10538 this.editing = false;
10540 this.store.afterReject(this);
10545 * Usually called by the {@link Roo.data.Store} which owns the Record.
10546 * Commits all changes made to the Record since either creation, or the last commit operation.
10548 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10549 * of commit operations.
10551 commit : function(){
10552 this.dirty = false;
10553 delete this.modified;
10554 this.editing = false;
10556 this.store.afterCommit(this);
10561 hasError : function(){
10562 return this.error != null;
10566 clearError : function(){
10571 * Creates a copy of this record.
10572 * @param {String} id (optional) A new record id if you don't want to use this record's id
10575 copy : function(newId) {
10576 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10580 * Ext JS Library 1.1.1
10581 * Copyright(c) 2006-2007, Ext JS, LLC.
10583 * Originally Released Under LGPL - original licence link has changed is not relivant.
10586 * <script type="text/javascript">
10592 * @class Roo.data.Store
10593 * @extends Roo.util.Observable
10594 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10595 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10597 * 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
10598 * has no knowledge of the format of the data returned by the Proxy.<br>
10600 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10601 * instances from the data object. These records are cached and made available through accessor functions.
10603 * Creates a new Store.
10604 * @param {Object} config A config object containing the objects needed for the Store to access data,
10605 * and read the data into Records.
10607 Roo.data.Store = function(config){
10608 this.data = new Roo.util.MixedCollection(false);
10609 this.data.getKey = function(o){
10612 this.baseParams = {};
10614 this.paramNames = {
10619 "multisort" : "_multisort"
10622 if(config && config.data){
10623 this.inlineData = config.data;
10624 delete config.data;
10627 Roo.apply(this, config);
10629 if(this.reader){ // reader passed
10630 this.reader = Roo.factory(this.reader, Roo.data);
10631 this.reader.xmodule = this.xmodule || false;
10632 if(!this.recordType){
10633 this.recordType = this.reader.recordType;
10635 if(this.reader.onMetaChange){
10636 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10640 if(this.recordType){
10641 this.fields = this.recordType.prototype.fields;
10643 this.modified = [];
10647 * @event datachanged
10648 * Fires when the data cache has changed, and a widget which is using this Store
10649 * as a Record cache should refresh its view.
10650 * @param {Store} this
10652 datachanged : true,
10654 * @event metachange
10655 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10656 * @param {Store} this
10657 * @param {Object} meta The JSON metadata
10662 * Fires when Records have been added to the Store
10663 * @param {Store} this
10664 * @param {Roo.data.Record[]} records The array of Records added
10665 * @param {Number} index The index at which the record(s) were added
10670 * Fires when a Record has been removed from the Store
10671 * @param {Store} this
10672 * @param {Roo.data.Record} record The Record that was removed
10673 * @param {Number} index The index at which the record was removed
10678 * Fires when a Record has been updated
10679 * @param {Store} this
10680 * @param {Roo.data.Record} record The Record that was updated
10681 * @param {String} operation The update operation being performed. Value may be one of:
10683 Roo.data.Record.EDIT
10684 Roo.data.Record.REJECT
10685 Roo.data.Record.COMMIT
10691 * Fires when the data cache has been cleared.
10692 * @param {Store} this
10696 * @event beforeload
10697 * Fires before a request is made for a new data object. If the beforeload handler returns false
10698 * the load action will be canceled.
10699 * @param {Store} this
10700 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10704 * @event beforeloadadd
10705 * Fires after a new set of Records has been loaded.
10706 * @param {Store} this
10707 * @param {Roo.data.Record[]} records The Records that were loaded
10708 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10710 beforeloadadd : true,
10713 * Fires after a new set of Records has been loaded, before they are added to the store.
10714 * @param {Store} this
10715 * @param {Roo.data.Record[]} records The Records that were loaded
10716 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10717 * @params {Object} return from reader
10721 * @event loadexception
10722 * Fires if an exception occurs in the Proxy during loading.
10723 * Called with the signature of the Proxy's "loadexception" event.
10724 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10727 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10728 * @param {Object} load options
10729 * @param {Object} jsonData from your request (normally this contains the Exception)
10731 loadexception : true
10735 this.proxy = Roo.factory(this.proxy, Roo.data);
10736 this.proxy.xmodule = this.xmodule || false;
10737 this.relayEvents(this.proxy, ["loadexception"]);
10739 this.sortToggle = {};
10740 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10742 Roo.data.Store.superclass.constructor.call(this);
10744 if(this.inlineData){
10745 this.loadData(this.inlineData);
10746 delete this.inlineData;
10750 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10752 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10753 * without a remote query - used by combo/forms at present.
10757 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10760 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10763 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10764 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10767 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10768 * on any HTTP request
10771 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10774 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10778 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10779 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10781 remoteSort : false,
10784 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10785 * loaded or when a record is removed. (defaults to false).
10787 pruneModifiedRecords : false,
10790 lastOptions : null,
10793 * Add Records to the Store and fires the add event.
10794 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10796 add : function(records){
10797 records = [].concat(records);
10798 for(var i = 0, len = records.length; i < len; i++){
10799 records[i].join(this);
10801 var index = this.data.length;
10802 this.data.addAll(records);
10803 this.fireEvent("add", this, records, index);
10807 * Remove a Record from the Store and fires the remove event.
10808 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10810 remove : function(record){
10811 var index = this.data.indexOf(record);
10812 this.data.removeAt(index);
10813 if(this.pruneModifiedRecords){
10814 this.modified.remove(record);
10816 this.fireEvent("remove", this, record, index);
10820 * Remove all Records from the Store and fires the clear event.
10822 removeAll : function(){
10824 if(this.pruneModifiedRecords){
10825 this.modified = [];
10827 this.fireEvent("clear", this);
10831 * Inserts Records to the Store at the given index and fires the add event.
10832 * @param {Number} index The start index at which to insert the passed Records.
10833 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10835 insert : function(index, records){
10836 records = [].concat(records);
10837 for(var i = 0, len = records.length; i < len; i++){
10838 this.data.insert(index, records[i]);
10839 records[i].join(this);
10841 this.fireEvent("add", this, records, index);
10845 * Get the index within the cache of the passed Record.
10846 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10847 * @return {Number} The index of the passed Record. Returns -1 if not found.
10849 indexOf : function(record){
10850 return this.data.indexOf(record);
10854 * Get the index within the cache of the Record with the passed id.
10855 * @param {String} id The id of the Record to find.
10856 * @return {Number} The index of the Record. Returns -1 if not found.
10858 indexOfId : function(id){
10859 return this.data.indexOfKey(id);
10863 * Get the Record with the specified id.
10864 * @param {String} id The id of the Record to find.
10865 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10867 getById : function(id){
10868 return this.data.key(id);
10872 * Get the Record at the specified index.
10873 * @param {Number} index The index of the Record to find.
10874 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10876 getAt : function(index){
10877 return this.data.itemAt(index);
10881 * Returns a range of Records between specified indices.
10882 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10883 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10884 * @return {Roo.data.Record[]} An array of Records
10886 getRange : function(start, end){
10887 return this.data.getRange(start, end);
10891 storeOptions : function(o){
10892 o = Roo.apply({}, o);
10895 this.lastOptions = o;
10899 * Loads the Record cache from the configured Proxy using the configured Reader.
10901 * If using remote paging, then the first load call must specify the <em>start</em>
10902 * and <em>limit</em> properties in the options.params property to establish the initial
10903 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10905 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10906 * and this call will return before the new data has been loaded. Perform any post-processing
10907 * in a callback function, or in a "load" event handler.</strong>
10909 * @param {Object} options An object containing properties which control loading options:<ul>
10910 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10911 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10912 * passed the following arguments:<ul>
10913 * <li>r : Roo.data.Record[]</li>
10914 * <li>options: Options object from the load call</li>
10915 * <li>success: Boolean success indicator</li></ul></li>
10916 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10917 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10920 load : function(options){
10921 options = options || {};
10922 if(this.fireEvent("beforeload", this, options) !== false){
10923 this.storeOptions(options);
10924 var p = Roo.apply(options.params || {}, this.baseParams);
10925 // if meta was not loaded from remote source.. try requesting it.
10926 if (!this.reader.metaFromRemote) {
10927 p._requestMeta = 1;
10929 if(this.sortInfo && this.remoteSort){
10930 var pn = this.paramNames;
10931 p[pn["sort"]] = this.sortInfo.field;
10932 p[pn["dir"]] = this.sortInfo.direction;
10934 if (this.multiSort) {
10935 var pn = this.paramNames;
10936 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10939 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10944 * Reloads the Record cache from the configured Proxy using the configured Reader and
10945 * the options from the last load operation performed.
10946 * @param {Object} options (optional) An object containing properties which may override the options
10947 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10948 * the most recently used options are reused).
10950 reload : function(options){
10951 this.load(Roo.applyIf(options||{}, this.lastOptions));
10955 // Called as a callback by the Reader during a load operation.
10956 loadRecords : function(o, options, success){
10957 if(!o || success === false){
10958 if(success !== false){
10959 this.fireEvent("load", this, [], options, o);
10961 if(options.callback){
10962 options.callback.call(options.scope || this, [], options, false);
10966 // if data returned failure - throw an exception.
10967 if (o.success === false) {
10968 // show a message if no listener is registered.
10969 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10970 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10972 // loadmask wil be hooked into this..
10973 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10976 var r = o.records, t = o.totalRecords || r.length;
10978 this.fireEvent("beforeloadadd", this, r, options, o);
10980 if(!options || options.add !== true){
10981 if(this.pruneModifiedRecords){
10982 this.modified = [];
10984 for(var i = 0, len = r.length; i < len; i++){
10988 this.data = this.snapshot;
10989 delete this.snapshot;
10992 this.data.addAll(r);
10993 this.totalLength = t;
10995 this.fireEvent("datachanged", this);
10997 this.totalLength = Math.max(t, this.data.length+r.length);
11000 this.fireEvent("load", this, r, options, o);
11001 if(options.callback){
11002 options.callback.call(options.scope || this, r, options, true);
11008 * Loads data from a passed data block. A Reader which understands the format of the data
11009 * must have been configured in the constructor.
11010 * @param {Object} data The data block from which to read the Records. The format of the data expected
11011 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11012 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11014 loadData : function(o, append){
11015 var r = this.reader.readRecords(o);
11016 this.loadRecords(r, {add: append}, true);
11020 * Gets the number of cached records.
11022 * <em>If using paging, this may not be the total size of the dataset. If the data object
11023 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11024 * the data set size</em>
11026 getCount : function(){
11027 return this.data.length || 0;
11031 * Gets the total number of records in the dataset as returned by the server.
11033 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11034 * the dataset size</em>
11036 getTotalCount : function(){
11037 return this.totalLength || 0;
11041 * Returns the sort state of the Store as an object with two properties:
11043 field {String} The name of the field by which the Records are sorted
11044 direction {String} The sort order, "ASC" or "DESC"
11047 getSortState : function(){
11048 return this.sortInfo;
11052 applySort : function(){
11053 if(this.sortInfo && !this.remoteSort){
11054 var s = this.sortInfo, f = s.field;
11055 var st = this.fields.get(f).sortType;
11056 var fn = function(r1, r2){
11057 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11058 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11060 this.data.sort(s.direction, fn);
11061 if(this.snapshot && this.snapshot != this.data){
11062 this.snapshot.sort(s.direction, fn);
11068 * Sets the default sort column and order to be used by the next load operation.
11069 * @param {String} fieldName The name of the field to sort by.
11070 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11072 setDefaultSort : function(field, dir){
11073 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11077 * Sort the Records.
11078 * If remote sorting is used, the sort is performed on the server, and the cache is
11079 * reloaded. If local sorting is used, the cache is sorted internally.
11080 * @param {String} fieldName The name of the field to sort by.
11081 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11083 sort : function(fieldName, dir){
11084 var f = this.fields.get(fieldName);
11086 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11088 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11089 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11094 this.sortToggle[f.name] = dir;
11095 this.sortInfo = {field: f.name, direction: dir};
11096 if(!this.remoteSort){
11098 this.fireEvent("datachanged", this);
11100 this.load(this.lastOptions);
11105 * Calls the specified function for each of the Records in the cache.
11106 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11107 * Returning <em>false</em> aborts and exits the iteration.
11108 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11110 each : function(fn, scope){
11111 this.data.each(fn, scope);
11115 * Gets all records modified since the last commit. Modified records are persisted across load operations
11116 * (e.g., during paging).
11117 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11119 getModifiedRecords : function(){
11120 return this.modified;
11124 createFilterFn : function(property, value, anyMatch){
11125 if(!value.exec){ // not a regex
11126 value = String(value);
11127 if(value.length == 0){
11130 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11132 return function(r){
11133 return value.test(r.data[property]);
11138 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11139 * @param {String} property A field on your records
11140 * @param {Number} start The record index to start at (defaults to 0)
11141 * @param {Number} end The last record index to include (defaults to length - 1)
11142 * @return {Number} The sum
11144 sum : function(property, start, end){
11145 var rs = this.data.items, v = 0;
11146 start = start || 0;
11147 end = (end || end === 0) ? end : rs.length-1;
11149 for(var i = start; i <= end; i++){
11150 v += (rs[i].data[property] || 0);
11156 * Filter the records by a specified property.
11157 * @param {String} field A field on your records
11158 * @param {String/RegExp} value Either a string that the field
11159 * should start with or a RegExp to test against the field
11160 * @param {Boolean} anyMatch True to match any part not just the beginning
11162 filter : function(property, value, anyMatch){
11163 var fn = this.createFilterFn(property, value, anyMatch);
11164 return fn ? this.filterBy(fn) : this.clearFilter();
11168 * Filter by a function. The specified function will be called with each
11169 * record in this data source. If the function returns true the record is included,
11170 * otherwise it is filtered.
11171 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11172 * @param {Object} scope (optional) The scope of the function (defaults to this)
11174 filterBy : function(fn, scope){
11175 this.snapshot = this.snapshot || this.data;
11176 this.data = this.queryBy(fn, scope||this);
11177 this.fireEvent("datachanged", this);
11181 * Query the records by a specified property.
11182 * @param {String} field A field on your records
11183 * @param {String/RegExp} value Either a string that the field
11184 * should start with or a RegExp to test against the field
11185 * @param {Boolean} anyMatch True to match any part not just the beginning
11186 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11188 query : function(property, value, anyMatch){
11189 var fn = this.createFilterFn(property, value, anyMatch);
11190 return fn ? this.queryBy(fn) : this.data.clone();
11194 * Query by a function. The specified function will be called with each
11195 * record in this data source. If the function returns true the record is included
11197 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11198 * @param {Object} scope (optional) The scope of the function (defaults to this)
11199 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11201 queryBy : function(fn, scope){
11202 var data = this.snapshot || this.data;
11203 return data.filterBy(fn, scope||this);
11207 * Collects unique values for a particular dataIndex from this store.
11208 * @param {String} dataIndex The property to collect
11209 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11210 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11211 * @return {Array} An array of the unique values
11213 collect : function(dataIndex, allowNull, bypassFilter){
11214 var d = (bypassFilter === true && this.snapshot) ?
11215 this.snapshot.items : this.data.items;
11216 var v, sv, r = [], l = {};
11217 for(var i = 0, len = d.length; i < len; i++){
11218 v = d[i].data[dataIndex];
11220 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11229 * Revert to a view of the Record cache with no filtering applied.
11230 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11232 clearFilter : function(suppressEvent){
11233 if(this.snapshot && this.snapshot != this.data){
11234 this.data = this.snapshot;
11235 delete this.snapshot;
11236 if(suppressEvent !== true){
11237 this.fireEvent("datachanged", this);
11243 afterEdit : function(record){
11244 if(this.modified.indexOf(record) == -1){
11245 this.modified.push(record);
11247 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11251 afterReject : function(record){
11252 this.modified.remove(record);
11253 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11257 afterCommit : function(record){
11258 this.modified.remove(record);
11259 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11263 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11264 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11266 commitChanges : function(){
11267 var m = this.modified.slice(0);
11268 this.modified = [];
11269 for(var i = 0, len = m.length; i < len; i++){
11275 * Cancel outstanding changes on all changed records.
11277 rejectChanges : function(){
11278 var m = this.modified.slice(0);
11279 this.modified = [];
11280 for(var i = 0, len = m.length; i < len; i++){
11285 onMetaChange : function(meta, rtype, o){
11286 this.recordType = rtype;
11287 this.fields = rtype.prototype.fields;
11288 delete this.snapshot;
11289 this.sortInfo = meta.sortInfo || this.sortInfo;
11290 this.modified = [];
11291 this.fireEvent('metachange', this, this.reader.meta);
11294 moveIndex : function(data, type)
11296 var index = this.indexOf(data);
11298 var newIndex = index + type;
11302 this.insert(newIndex, data);
11307 * Ext JS Library 1.1.1
11308 * Copyright(c) 2006-2007, Ext JS, LLC.
11310 * Originally Released Under LGPL - original licence link has changed is not relivant.
11313 * <script type="text/javascript">
11317 * @class Roo.data.SimpleStore
11318 * @extends Roo.data.Store
11319 * Small helper class to make creating Stores from Array data easier.
11320 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11321 * @cfg {Array} fields An array of field definition objects, or field name strings.
11322 * @cfg {Array} data The multi-dimensional array of data
11324 * @param {Object} config
11326 Roo.data.SimpleStore = function(config){
11327 Roo.data.SimpleStore.superclass.constructor.call(this, {
11329 reader: new Roo.data.ArrayReader({
11332 Roo.data.Record.create(config.fields)
11334 proxy : new Roo.data.MemoryProxy(config.data)
11338 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11340 * Ext JS Library 1.1.1
11341 * Copyright(c) 2006-2007, Ext JS, LLC.
11343 * Originally Released Under LGPL - original licence link has changed is not relivant.
11346 * <script type="text/javascript">
11351 * @extends Roo.data.Store
11352 * @class Roo.data.JsonStore
11353 * Small helper class to make creating Stores for JSON data easier. <br/>
11355 var store = new Roo.data.JsonStore({
11356 url: 'get-images.php',
11358 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11361 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11362 * JsonReader and HttpProxy (unless inline data is provided).</b>
11363 * @cfg {Array} fields An array of field definition objects, or field name strings.
11365 * @param {Object} config
11367 Roo.data.JsonStore = function(c){
11368 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11369 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11370 reader: new Roo.data.JsonReader(c, c.fields)
11373 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11375 * Ext JS Library 1.1.1
11376 * Copyright(c) 2006-2007, Ext JS, LLC.
11378 * Originally Released Under LGPL - original licence link has changed is not relivant.
11381 * <script type="text/javascript">
11385 Roo.data.Field = function(config){
11386 if(typeof config == "string"){
11387 config = {name: config};
11389 Roo.apply(this, config);
11392 this.type = "auto";
11395 var st = Roo.data.SortTypes;
11396 // named sortTypes are supported, here we look them up
11397 if(typeof this.sortType == "string"){
11398 this.sortType = st[this.sortType];
11401 // set default sortType for strings and dates
11402 if(!this.sortType){
11405 this.sortType = st.asUCString;
11408 this.sortType = st.asDate;
11411 this.sortType = st.none;
11416 var stripRe = /[\$,%]/g;
11418 // prebuilt conversion function for this field, instead of
11419 // switching every time we're reading a value
11421 var cv, dateFormat = this.dateFormat;
11426 cv = function(v){ return v; };
11429 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11433 return v !== undefined && v !== null && v !== '' ?
11434 parseInt(String(v).replace(stripRe, ""), 10) : '';
11439 return v !== undefined && v !== null && v !== '' ?
11440 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11445 cv = function(v){ return v === true || v === "true" || v == 1; };
11452 if(v instanceof Date){
11456 if(dateFormat == "timestamp"){
11457 return new Date(v*1000);
11459 return Date.parseDate(v, dateFormat);
11461 var parsed = Date.parse(v);
11462 return parsed ? new Date(parsed) : null;
11471 Roo.data.Field.prototype = {
11479 * Ext JS Library 1.1.1
11480 * Copyright(c) 2006-2007, Ext JS, LLC.
11482 * Originally Released Under LGPL - original licence link has changed is not relivant.
11485 * <script type="text/javascript">
11488 // Base class for reading structured data from a data source. This class is intended to be
11489 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11492 * @class Roo.data.DataReader
11493 * Base class for reading structured data from a data source. This class is intended to be
11494 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11497 Roo.data.DataReader = function(meta, recordType){
11501 this.recordType = recordType instanceof Array ?
11502 Roo.data.Record.create(recordType) : recordType;
11505 Roo.data.DataReader.prototype = {
11507 * Create an empty record
11508 * @param {Object} data (optional) - overlay some values
11509 * @return {Roo.data.Record} record created.
11511 newRow : function(d) {
11513 this.recordType.prototype.fields.each(function(c) {
11515 case 'int' : da[c.name] = 0; break;
11516 case 'date' : da[c.name] = new Date(); break;
11517 case 'float' : da[c.name] = 0.0; break;
11518 case 'boolean' : da[c.name] = false; break;
11519 default : da[c.name] = ""; break;
11523 return new this.recordType(Roo.apply(da, d));
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">
11538 * @class Roo.data.DataProxy
11539 * @extends Roo.data.Observable
11540 * This class is an abstract base class for implementations which provide retrieval of
11541 * unformatted data objects.<br>
11543 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11544 * (of the appropriate type which knows how to parse the data object) to provide a block of
11545 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11547 * Custom implementations must implement the load method as described in
11548 * {@link Roo.data.HttpProxy#load}.
11550 Roo.data.DataProxy = function(){
11553 * @event beforeload
11554 * Fires before a network request is made to retrieve a data object.
11555 * @param {Object} This DataProxy object.
11556 * @param {Object} params The params parameter to the load function.
11561 * Fires before the load method's callback is called.
11562 * @param {Object} This DataProxy object.
11563 * @param {Object} o The data object.
11564 * @param {Object} arg The callback argument object passed to the load function.
11568 * @event loadexception
11569 * Fires if an Exception occurs during data retrieval.
11570 * @param {Object} This DataProxy object.
11571 * @param {Object} o The data object.
11572 * @param {Object} arg The callback argument object passed to the load function.
11573 * @param {Object} e The Exception.
11575 loadexception : true
11577 Roo.data.DataProxy.superclass.constructor.call(this);
11580 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11583 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11587 * Ext JS Library 1.1.1
11588 * Copyright(c) 2006-2007, Ext JS, LLC.
11590 * Originally Released Under LGPL - original licence link has changed is not relivant.
11593 * <script type="text/javascript">
11596 * @class Roo.data.MemoryProxy
11597 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11598 * to the Reader when its load method is called.
11600 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11602 Roo.data.MemoryProxy = function(data){
11606 Roo.data.MemoryProxy.superclass.constructor.call(this);
11610 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11613 * Load data from the requested source (in this case an in-memory
11614 * data object passed to the constructor), read the data object into
11615 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11616 * process that block using the passed callback.
11617 * @param {Object} params This parameter is not used by the MemoryProxy class.
11618 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11619 * object into a block of Roo.data.Records.
11620 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11621 * The function must be passed <ul>
11622 * <li>The Record block object</li>
11623 * <li>The "arg" argument from the load function</li>
11624 * <li>A boolean success indicator</li>
11626 * @param {Object} scope The scope in which to call the callback
11627 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11629 load : function(params, reader, callback, scope, arg){
11630 params = params || {};
11633 result = reader.readRecords(this.data);
11635 this.fireEvent("loadexception", this, arg, null, e);
11636 callback.call(scope, null, arg, false);
11639 callback.call(scope, result, arg, true);
11643 update : function(params, records){
11648 * Ext JS Library 1.1.1
11649 * Copyright(c) 2006-2007, Ext JS, LLC.
11651 * Originally Released Under LGPL - original licence link has changed is not relivant.
11654 * <script type="text/javascript">
11657 * @class Roo.data.HttpProxy
11658 * @extends Roo.data.DataProxy
11659 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11660 * configured to reference a certain URL.<br><br>
11662 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11663 * from which the running page was served.<br><br>
11665 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11667 * Be aware that to enable the browser to parse an XML document, the server must set
11668 * the Content-Type header in the HTTP response to "text/xml".
11670 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11671 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11672 * will be used to make the request.
11674 Roo.data.HttpProxy = function(conn){
11675 Roo.data.HttpProxy.superclass.constructor.call(this);
11676 // is conn a conn config or a real conn?
11678 this.useAjax = !conn || !conn.events;
11682 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11683 // thse are take from connection...
11686 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11689 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11690 * extra parameters to each request made by this object. (defaults to undefined)
11693 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11694 * to each request made by this object. (defaults to undefined)
11697 * @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)
11700 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11703 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11709 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11713 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11714 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11715 * a finer-grained basis than the DataProxy events.
11717 getConnection : function(){
11718 return this.useAjax ? Roo.Ajax : this.conn;
11722 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11723 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11724 * process that block using the passed callback.
11725 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11726 * for the request to the remote server.
11727 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11728 * object into a block of Roo.data.Records.
11729 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11730 * The function must be passed <ul>
11731 * <li>The Record block object</li>
11732 * <li>The "arg" argument from the load function</li>
11733 * <li>A boolean success indicator</li>
11735 * @param {Object} scope The scope in which to call the callback
11736 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11738 load : function(params, reader, callback, scope, arg){
11739 if(this.fireEvent("beforeload", this, params) !== false){
11741 params : params || {},
11743 callback : callback,
11748 callback : this.loadResponse,
11752 Roo.applyIf(o, this.conn);
11753 if(this.activeRequest){
11754 Roo.Ajax.abort(this.activeRequest);
11756 this.activeRequest = Roo.Ajax.request(o);
11758 this.conn.request(o);
11761 callback.call(scope||this, null, arg, false);
11766 loadResponse : function(o, success, response){
11767 delete this.activeRequest;
11769 this.fireEvent("loadexception", this, o, response);
11770 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11775 result = o.reader.read(response);
11777 this.fireEvent("loadexception", this, o, response, e);
11778 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11782 this.fireEvent("load", this, o, o.request.arg);
11783 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11787 update : function(dataSet){
11792 updateResponse : function(dataSet){
11797 * Ext JS Library 1.1.1
11798 * Copyright(c) 2006-2007, Ext JS, LLC.
11800 * Originally Released Under LGPL - original licence link has changed is not relivant.
11803 * <script type="text/javascript">
11807 * @class Roo.data.ScriptTagProxy
11808 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11809 * other than the originating domain of the running page.<br><br>
11811 * <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
11812 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11814 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11815 * source code that is used as the source inside a <script> tag.<br><br>
11817 * In order for the browser to process the returned data, the server must wrap the data object
11818 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11819 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11820 * depending on whether the callback name was passed:
11823 boolean scriptTag = false;
11824 String cb = request.getParameter("callback");
11827 response.setContentType("text/javascript");
11829 response.setContentType("application/x-json");
11831 Writer out = response.getWriter();
11833 out.write(cb + "(");
11835 out.print(dataBlock.toJsonString());
11842 * @param {Object} config A configuration object.
11844 Roo.data.ScriptTagProxy = function(config){
11845 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11846 Roo.apply(this, config);
11847 this.head = document.getElementsByTagName("head")[0];
11850 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11852 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11854 * @cfg {String} url The URL from which to request the data object.
11857 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11861 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11862 * the server the name of the callback function set up by the load call to process the returned data object.
11863 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11864 * javascript output which calls this named function passing the data object as its only parameter.
11866 callbackParam : "callback",
11868 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11869 * name to the request.
11874 * Load data from the configured URL, read the data object into
11875 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11876 * process that block using the passed callback.
11877 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11878 * for the request to the remote server.
11879 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11880 * object into a block of Roo.data.Records.
11881 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11882 * The function must be passed <ul>
11883 * <li>The Record block object</li>
11884 * <li>The "arg" argument from the load function</li>
11885 * <li>A boolean success indicator</li>
11887 * @param {Object} scope The scope in which to call the callback
11888 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11890 load : function(params, reader, callback, scope, arg){
11891 if(this.fireEvent("beforeload", this, params) !== false){
11893 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11895 var url = this.url;
11896 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11898 url += "&_dc=" + (new Date().getTime());
11900 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11903 cb : "stcCallback"+transId,
11904 scriptId : "stcScript"+transId,
11908 callback : callback,
11914 window[trans.cb] = function(o){
11915 conn.handleResponse(o, trans);
11918 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11920 if(this.autoAbort !== false){
11924 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11926 var script = document.createElement("script");
11927 script.setAttribute("src", url);
11928 script.setAttribute("type", "text/javascript");
11929 script.setAttribute("id", trans.scriptId);
11930 this.head.appendChild(script);
11932 this.trans = trans;
11934 callback.call(scope||this, null, arg, false);
11939 isLoading : function(){
11940 return this.trans ? true : false;
11944 * Abort the current server request.
11946 abort : function(){
11947 if(this.isLoading()){
11948 this.destroyTrans(this.trans);
11953 destroyTrans : function(trans, isLoaded){
11954 this.head.removeChild(document.getElementById(trans.scriptId));
11955 clearTimeout(trans.timeoutId);
11957 window[trans.cb] = undefined;
11959 delete window[trans.cb];
11962 // if hasn't been loaded, wait for load to remove it to prevent script error
11963 window[trans.cb] = function(){
11964 window[trans.cb] = undefined;
11966 delete window[trans.cb];
11973 handleResponse : function(o, trans){
11974 this.trans = false;
11975 this.destroyTrans(trans, true);
11978 result = trans.reader.readRecords(o);
11980 this.fireEvent("loadexception", this, o, trans.arg, e);
11981 trans.callback.call(trans.scope||window, null, trans.arg, false);
11984 this.fireEvent("load", this, o, trans.arg);
11985 trans.callback.call(trans.scope||window, result, trans.arg, true);
11989 handleFailure : function(trans){
11990 this.trans = false;
11991 this.destroyTrans(trans, false);
11992 this.fireEvent("loadexception", this, null, trans.arg);
11993 trans.callback.call(trans.scope||window, null, trans.arg, false);
11997 * Ext JS Library 1.1.1
11998 * Copyright(c) 2006-2007, Ext JS, LLC.
12000 * Originally Released Under LGPL - original licence link has changed is not relivant.
12003 * <script type="text/javascript">
12007 * @class Roo.data.JsonReader
12008 * @extends Roo.data.DataReader
12009 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12010 * based on mappings in a provided Roo.data.Record constructor.
12012 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12013 * in the reply previously.
12018 var RecordDef = Roo.data.Record.create([
12019 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12020 {name: 'occupation'} // This field will use "occupation" as the mapping.
12022 var myReader = new Roo.data.JsonReader({
12023 totalProperty: "results", // The property which contains the total dataset size (optional)
12024 root: "rows", // The property which contains an Array of row objects
12025 id: "id" // The property within each row object that provides an ID for the record (optional)
12029 * This would consume a JSON file like this:
12031 { 'results': 2, 'rows': [
12032 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12033 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12036 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12037 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12038 * paged from the remote server.
12039 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12040 * @cfg {String} root name of the property which contains the Array of row objects.
12041 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12042 * @cfg {Array} fields Array of field definition objects
12044 * Create a new JsonReader
12045 * @param {Object} meta Metadata configuration options
12046 * @param {Object} recordType Either an Array of field definition objects,
12047 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12049 Roo.data.JsonReader = function(meta, recordType){
12052 // set some defaults:
12053 Roo.applyIf(meta, {
12054 totalProperty: 'total',
12055 successProperty : 'success',
12060 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12062 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12065 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12066 * Used by Store query builder to append _requestMeta to params.
12069 metaFromRemote : false,
12071 * This method is only used by a DataProxy which has retrieved data from a remote server.
12072 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12073 * @return {Object} data A data block which is used by an Roo.data.Store object as
12074 * a cache of Roo.data.Records.
12076 read : function(response){
12077 var json = response.responseText;
12079 var o = /* eval:var:o */ eval("("+json+")");
12081 throw {message: "JsonReader.read: Json object not found"};
12087 this.metaFromRemote = true;
12088 this.meta = o.metaData;
12089 this.recordType = Roo.data.Record.create(o.metaData.fields);
12090 this.onMetaChange(this.meta, this.recordType, o);
12092 return this.readRecords(o);
12095 // private function a store will implement
12096 onMetaChange : function(meta, recordType, o){
12103 simpleAccess: function(obj, subsc) {
12110 getJsonAccessor: function(){
12112 return function(expr) {
12114 return(re.test(expr))
12115 ? new Function("obj", "return obj." + expr)
12120 return Roo.emptyFn;
12125 * Create a data block containing Roo.data.Records from an XML document.
12126 * @param {Object} o An object which contains an Array of row objects in the property specified
12127 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12128 * which contains the total size of the dataset.
12129 * @return {Object} data A data block which is used by an Roo.data.Store object as
12130 * a cache of Roo.data.Records.
12132 readRecords : function(o){
12134 * After any data loads, the raw JSON data is available for further custom processing.
12138 var s = this.meta, Record = this.recordType,
12139 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12141 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12143 if(s.totalProperty) {
12144 this.getTotal = this.getJsonAccessor(s.totalProperty);
12146 if(s.successProperty) {
12147 this.getSuccess = this.getJsonAccessor(s.successProperty);
12149 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12151 var g = this.getJsonAccessor(s.id);
12152 this.getId = function(rec) {
12154 return (r === undefined || r === "") ? null : r;
12157 this.getId = function(){return null;};
12160 for(var jj = 0; jj < fl; jj++){
12162 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12163 this.ef[jj] = this.getJsonAccessor(map);
12167 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12168 if(s.totalProperty){
12169 var vt = parseInt(this.getTotal(o), 10);
12174 if(s.successProperty){
12175 var vs = this.getSuccess(o);
12176 if(vs === false || vs === 'false'){
12181 for(var i = 0; i < c; i++){
12184 var id = this.getId(n);
12185 for(var j = 0; j < fl; j++){
12187 var v = this.ef[j](n);
12189 Roo.log('missing convert for ' + f.name);
12193 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12195 var record = new Record(values, id);
12197 records[i] = record;
12203 totalRecords : totalRecords
12208 * Ext JS Library 1.1.1
12209 * Copyright(c) 2006-2007, Ext JS, LLC.
12211 * Originally Released Under LGPL - original licence link has changed is not relivant.
12214 * <script type="text/javascript">
12218 * @class Roo.data.ArrayReader
12219 * @extends Roo.data.DataReader
12220 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12221 * Each element of that Array represents a row of data fields. The
12222 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12223 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12227 var RecordDef = Roo.data.Record.create([
12228 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12229 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12231 var myReader = new Roo.data.ArrayReader({
12232 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12236 * This would consume an Array like this:
12238 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12240 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12242 * Create a new JsonReader
12243 * @param {Object} meta Metadata configuration options.
12244 * @param {Object} recordType Either an Array of field definition objects
12245 * as specified to {@link Roo.data.Record#create},
12246 * or an {@link Roo.data.Record} object
12247 * created using {@link Roo.data.Record#create}.
12249 Roo.data.ArrayReader = function(meta, recordType){
12250 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12253 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12255 * Create a data block containing Roo.data.Records from an XML document.
12256 * @param {Object} o An Array of row objects which represents the dataset.
12257 * @return {Object} data A data block which is used by an Roo.data.Store object as
12258 * a cache of Roo.data.Records.
12260 readRecords : function(o){
12261 var sid = this.meta ? this.meta.id : null;
12262 var recordType = this.recordType, fields = recordType.prototype.fields;
12265 for(var i = 0; i < root.length; i++){
12268 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12269 for(var j = 0, jlen = fields.length; j < jlen; j++){
12270 var f = fields.items[j];
12271 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12272 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12274 values[f.name] = v;
12276 var record = new recordType(values, id);
12278 records[records.length] = record;
12282 totalRecords : records.length
12291 * @class Roo.bootstrap.ComboBox
12292 * @extends Roo.bootstrap.TriggerField
12293 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12294 * @cfg {Boolean} append (true|false) default false
12295 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12296 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12297 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12298 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12299 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12300 * @cfg {Boolean} animate default true
12301 * @cfg {Boolean} emptyResultText only for touch device
12302 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12304 * Create a new ComboBox.
12305 * @param {Object} config Configuration options
12307 Roo.bootstrap.ComboBox = function(config){
12308 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12312 * Fires when the dropdown list is expanded
12313 * @param {Roo.bootstrap.ComboBox} combo This combo box
12318 * Fires when the dropdown list is collapsed
12319 * @param {Roo.bootstrap.ComboBox} combo This combo box
12323 * @event beforeselect
12324 * Fires before a list item is selected. Return false to cancel the selection.
12325 * @param {Roo.bootstrap.ComboBox} combo This combo box
12326 * @param {Roo.data.Record} record The data record returned from the underlying store
12327 * @param {Number} index The index of the selected item in the dropdown list
12329 'beforeselect' : true,
12332 * Fires when a list item is selected
12333 * @param {Roo.bootstrap.ComboBox} combo This combo box
12334 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12335 * @param {Number} index The index of the selected item in the dropdown list
12339 * @event beforequery
12340 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12341 * The event object passed has these properties:
12342 * @param {Roo.bootstrap.ComboBox} combo This combo box
12343 * @param {String} query The query
12344 * @param {Boolean} forceAll true to force "all" query
12345 * @param {Boolean} cancel true to cancel the query
12346 * @param {Object} e The query event object
12348 'beforequery': true,
12351 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12352 * @param {Roo.bootstrap.ComboBox} combo This combo box
12357 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12358 * @param {Roo.bootstrap.ComboBox} combo This combo box
12359 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12364 * Fires when the remove value from the combobox array
12365 * @param {Roo.bootstrap.ComboBox} combo This combo box
12369 * @event afterremove
12370 * Fires when the remove value from the combobox array
12371 * @param {Roo.bootstrap.ComboBox} combo This combo box
12373 'afterremove' : true,
12375 * @event specialfilter
12376 * Fires when specialfilter
12377 * @param {Roo.bootstrap.ComboBox} combo This combo box
12379 'specialfilter' : true,
12382 * Fires when tick the element
12383 * @param {Roo.bootstrap.ComboBox} combo This combo box
12387 * @event touchviewdisplay
12388 * Fires when touch view require special display (default is using displayField)
12389 * @param {Roo.bootstrap.ComboBox} combo This combo box
12390 * @param {Object} cfg set html .
12392 'touchviewdisplay' : true
12397 this.tickItems = [];
12399 this.selectedIndex = -1;
12400 if(this.mode == 'local'){
12401 if(config.queryDelay === undefined){
12402 this.queryDelay = 10;
12404 if(config.minChars === undefined){
12410 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12413 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12414 * rendering into an Roo.Editor, defaults to false)
12417 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12418 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12421 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12424 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12425 * the dropdown list (defaults to undefined, with no header element)
12429 * @cfg {String/Roo.Template} tpl The template to use to render the output
12433 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12435 listWidth: undefined,
12437 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12438 * mode = 'remote' or 'text' if mode = 'local')
12440 displayField: undefined,
12443 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12444 * mode = 'remote' or 'value' if mode = 'local').
12445 * Note: use of a valueField requires the user make a selection
12446 * in order for a value to be mapped.
12448 valueField: undefined,
12450 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12455 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12456 * field's data value (defaults to the underlying DOM element's name)
12458 hiddenName: undefined,
12460 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12464 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12466 selectedClass: 'active',
12469 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12473 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12474 * anchor positions (defaults to 'tl-bl')
12476 listAlign: 'tl-bl?',
12478 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12482 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12483 * query specified by the allQuery config option (defaults to 'query')
12485 triggerAction: 'query',
12487 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12488 * (defaults to 4, does not apply if editable = false)
12492 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12493 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12497 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12498 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12502 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12503 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12507 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12508 * when editable = true (defaults to false)
12510 selectOnFocus:false,
12512 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12514 queryParam: 'query',
12516 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12517 * when mode = 'remote' (defaults to 'Loading...')
12519 loadingText: 'Loading...',
12521 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12525 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12529 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12530 * traditional select (defaults to true)
12534 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12538 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12542 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12543 * listWidth has a higher value)
12547 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12548 * allow the user to set arbitrary text into the field (defaults to false)
12550 forceSelection:false,
12552 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12553 * if typeAhead = true (defaults to 250)
12555 typeAheadDelay : 250,
12557 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12558 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12560 valueNotFoundText : undefined,
12562 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12564 blockFocus : false,
12567 * @cfg {Boolean} disableClear Disable showing of clear button.
12569 disableClear : false,
12571 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12573 alwaysQuery : false,
12576 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12581 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12583 invalidClass : "has-warning",
12586 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12588 validClass : "has-success",
12591 * @cfg {Boolean} specialFilter (true|false) special filter default false
12593 specialFilter : false,
12596 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12598 mobileTouchView : true,
12601 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12603 useNativeIOS : false,
12605 ios_options : false,
12617 btnPosition : 'right',
12618 triggerList : true,
12619 showToggleBtn : true,
12621 emptyResultText: 'Empty',
12622 triggerText : 'Select',
12624 // element that contains real text value.. (when hidden is used..)
12626 getAutoCreate : function()
12631 * Render classic select for iso
12634 if(Roo.isIOS && this.useNativeIOS){
12635 cfg = this.getAutoCreateNativeIOS();
12643 if(Roo.isTouch && this.mobileTouchView){
12644 cfg = this.getAutoCreateTouchView();
12651 if(!this.tickable){
12652 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12653 if(this.name == 'info_year_invest_id_display_name'){
12654 Roo.log('cfg.................................................');
12661 * ComboBox with tickable selections
12664 var align = this.labelAlign || this.parentLabelAlign();
12667 cls : 'form-group roo-combobox-tickable' //input-group
12670 var btn_text_select = '';
12671 var btn_text_done = '';
12672 var btn_text_cancel = '';
12674 if (this.btn_text_show) {
12675 btn_text_select = 'Select';
12676 btn_text_done = 'Done';
12677 btn_text_cancel = 'Cancel';
12682 cls : 'tickable-buttons',
12687 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12688 //html : this.triggerText
12689 html: btn_text_select
12695 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12697 html: btn_text_done
12703 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12705 html: btn_text_cancel
12711 buttons.cn.unshift({
12713 cls: 'roo-select2-search-field-input'
12719 Roo.each(buttons.cn, function(c){
12721 c.cls += ' btn-' + _this.size;
12724 if (_this.disabled) {
12735 cls: 'form-hidden-field'
12739 cls: 'roo-select2-choices',
12743 cls: 'roo-select2-search-field',
12754 cls: 'roo-select2-container input-group roo-select2-container-multi',
12759 // cls: 'typeahead typeahead-long dropdown-menu',
12760 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12765 if(this.hasFeedback && !this.allowBlank){
12769 cls: 'glyphicon form-control-feedback'
12772 combobox.cn.push(feedback);
12776 if (align ==='left' && this.fieldLabel.length) {
12778 cfg.cls += ' roo-form-group-label-left';
12783 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12784 tooltip : 'This field is required'
12789 cls : 'control-label',
12790 html : this.fieldLabel
12802 var labelCfg = cfg.cn[1];
12803 var contentCfg = cfg.cn[2];
12806 if(this.indicatorpos == 'right'){
12812 cls : 'control-label',
12816 html : this.fieldLabel
12820 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12821 tooltip : 'This field is required'
12836 labelCfg = cfg.cn[0];
12837 contentCfg = cfg.cn[1];
12841 if(this.labelWidth > 12){
12842 labelCfg.style = "width: " + this.labelWidth + 'px';
12845 if(this.labelWidth < 13 && this.labelmd == 0){
12846 this.labelmd = this.labelWidth;
12849 if(this.labellg > 0){
12850 labelCfg.cls += ' col-lg-' + this.labellg;
12851 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12854 if(this.labelmd > 0){
12855 labelCfg.cls += ' col-md-' + this.labelmd;
12856 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12859 if(this.labelsm > 0){
12860 labelCfg.cls += ' col-sm-' + this.labelsm;
12861 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12864 if(this.labelxs > 0){
12865 labelCfg.cls += ' col-xs-' + this.labelxs;
12866 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12870 } else if ( this.fieldLabel.length) {
12871 // Roo.log(" label");
12875 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12876 tooltip : 'This field is required'
12880 //cls : 'input-group-addon',
12881 html : this.fieldLabel
12889 if(this.indicatorpos == 'right'){
12894 //cls : 'input-group-addon',
12898 html : this.fieldLabel
12902 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12903 tooltip : 'This field is required'
12918 // Roo.log(" no label && no align");
12925 ['xs','sm','md','lg'].map(function(size){
12926 if (settings[size]) {
12927 cfg.cls += ' col-' + size + '-' + settings[size];
12935 _initEventsCalled : false,
12938 initEvents: function()
12940 if (this._initEventsCalled) { // as we call render... prevent looping...
12943 this._initEventsCalled = true;
12946 throw "can not find store for combo";
12949 this.store = Roo.factory(this.store, Roo.data);
12951 // if we are building from html. then this element is so complex, that we can not really
12952 // use the rendered HTML.
12953 // so we have to trash and replace the previous code.
12954 if (Roo.XComponent.build_from_html) {
12956 // remove this element....
12957 var e = this.el.dom, k=0;
12958 while (e ) { e = e.previousSibling; ++k;}
12963 this.rendered = false;
12965 this.render(this.parent().getChildContainer(true), k);
12971 if(Roo.isIOS && this.useNativeIOS){
12972 this.initIOSView();
12980 if(Roo.isTouch && this.mobileTouchView){
12981 this.initTouchView();
12986 this.initTickableEvents();
12990 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12992 if(this.hiddenName){
12994 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12996 this.hiddenField.dom.value =
12997 this.hiddenValue !== undefined ? this.hiddenValue :
12998 this.value !== undefined ? this.value : '';
13000 // prevent input submission
13001 this.el.dom.removeAttribute('name');
13002 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13007 // this.el.dom.setAttribute('autocomplete', 'off');
13010 var cls = 'x-combo-list';
13012 //this.list = new Roo.Layer({
13013 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13019 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13020 _this.list.setWidth(lw);
13023 this.list.on('mouseover', this.onViewOver, this);
13024 this.list.on('mousemove', this.onViewMove, this);
13026 this.list.on('scroll', this.onViewScroll, this);
13029 this.list.swallowEvent('mousewheel');
13030 this.assetHeight = 0;
13033 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13034 this.assetHeight += this.header.getHeight();
13037 this.innerList = this.list.createChild({cls:cls+'-inner'});
13038 this.innerList.on('mouseover', this.onViewOver, this);
13039 this.innerList.on('mousemove', this.onViewMove, this);
13040 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13042 if(this.allowBlank && !this.pageSize && !this.disableClear){
13043 this.footer = this.list.createChild({cls:cls+'-ft'});
13044 this.pageTb = new Roo.Toolbar(this.footer);
13048 this.footer = this.list.createChild({cls:cls+'-ft'});
13049 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13050 {pageSize: this.pageSize});
13054 if (this.pageTb && this.allowBlank && !this.disableClear) {
13056 this.pageTb.add(new Roo.Toolbar.Fill(), {
13057 cls: 'x-btn-icon x-btn-clear',
13059 handler: function()
13062 _this.clearValue();
13063 _this.onSelect(false, -1);
13068 this.assetHeight += this.footer.getHeight();
13073 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13076 this.view = new Roo.View(this.list, this.tpl, {
13077 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13079 //this.view.wrapEl.setDisplayed(false);
13080 this.view.on('click', this.onViewClick, this);
13084 this.store.on('beforeload', this.onBeforeLoad, this);
13085 this.store.on('load', this.onLoad, this);
13086 this.store.on('loadexception', this.onLoadException, this);
13088 if(this.resizable){
13089 this.resizer = new Roo.Resizable(this.list, {
13090 pinned:true, handles:'se'
13092 this.resizer.on('resize', function(r, w, h){
13093 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13094 this.listWidth = w;
13095 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13096 this.restrictHeight();
13098 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13101 if(!this.editable){
13102 this.editable = true;
13103 this.setEditable(false);
13108 if (typeof(this.events.add.listeners) != 'undefined') {
13110 this.addicon = this.wrap.createChild(
13111 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13113 this.addicon.on('click', function(e) {
13114 this.fireEvent('add', this);
13117 if (typeof(this.events.edit.listeners) != 'undefined') {
13119 this.editicon = this.wrap.createChild(
13120 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13121 if (this.addicon) {
13122 this.editicon.setStyle('margin-left', '40px');
13124 this.editicon.on('click', function(e) {
13126 // we fire even if inothing is selected..
13127 this.fireEvent('edit', this, this.lastData );
13133 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13134 "up" : function(e){
13135 this.inKeyMode = true;
13139 "down" : function(e){
13140 if(!this.isExpanded()){
13141 this.onTriggerClick();
13143 this.inKeyMode = true;
13148 "enter" : function(e){
13149 // this.onViewClick();
13153 if(this.fireEvent("specialkey", this, e)){
13154 this.onViewClick(false);
13160 "esc" : function(e){
13164 "tab" : function(e){
13167 if(this.fireEvent("specialkey", this, e)){
13168 this.onViewClick(false);
13176 doRelay : function(foo, bar, hname){
13177 if(hname == 'down' || this.scope.isExpanded()){
13178 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13187 this.queryDelay = Math.max(this.queryDelay || 10,
13188 this.mode == 'local' ? 10 : 250);
13191 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13193 if(this.typeAhead){
13194 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13196 if(this.editable !== false){
13197 this.inputEl().on("keyup", this.onKeyUp, this);
13199 if(this.forceSelection){
13200 this.inputEl().on('blur', this.doForce, this);
13204 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13205 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13209 initTickableEvents: function()
13213 if(this.hiddenName){
13215 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13217 this.hiddenField.dom.value =
13218 this.hiddenValue !== undefined ? this.hiddenValue :
13219 this.value !== undefined ? this.value : '';
13221 // prevent input submission
13222 this.el.dom.removeAttribute('name');
13223 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13228 // this.list = this.el.select('ul.dropdown-menu',true).first();
13230 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13231 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13232 if(this.triggerList){
13233 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13236 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13237 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13239 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13240 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13242 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13243 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13245 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13246 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13247 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13250 this.cancelBtn.hide();
13255 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13256 _this.list.setWidth(lw);
13259 this.list.on('mouseover', this.onViewOver, this);
13260 this.list.on('mousemove', this.onViewMove, this);
13262 this.list.on('scroll', this.onViewScroll, this);
13265 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>';
13268 this.view = new Roo.View(this.list, this.tpl, {
13269 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13272 //this.view.wrapEl.setDisplayed(false);
13273 this.view.on('click', this.onViewClick, this);
13277 this.store.on('beforeload', this.onBeforeLoad, this);
13278 this.store.on('load', this.onLoad, this);
13279 this.store.on('loadexception', this.onLoadException, this);
13282 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13283 "up" : function(e){
13284 this.inKeyMode = true;
13288 "down" : function(e){
13289 this.inKeyMode = true;
13293 "enter" : function(e){
13294 if(this.fireEvent("specialkey", this, e)){
13295 this.onViewClick(false);
13301 "esc" : function(e){
13302 this.onTickableFooterButtonClick(e, false, false);
13305 "tab" : function(e){
13306 this.fireEvent("specialkey", this, e);
13308 this.onTickableFooterButtonClick(e, false, false);
13315 doRelay : function(e, fn, key){
13316 if(this.scope.isExpanded()){
13317 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13326 this.queryDelay = Math.max(this.queryDelay || 10,
13327 this.mode == 'local' ? 10 : 250);
13330 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13332 if(this.typeAhead){
13333 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13336 if(this.editable !== false){
13337 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13340 this.indicator = this.indicatorEl();
13342 if(this.indicator){
13343 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13344 this.indicator.hide();
13349 onDestroy : function(){
13351 this.view.setStore(null);
13352 this.view.el.removeAllListeners();
13353 this.view.el.remove();
13354 this.view.purgeListeners();
13357 this.list.dom.innerHTML = '';
13361 this.store.un('beforeload', this.onBeforeLoad, this);
13362 this.store.un('load', this.onLoad, this);
13363 this.store.un('loadexception', this.onLoadException, this);
13365 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13369 fireKey : function(e){
13370 if(e.isNavKeyPress() && !this.list.isVisible()){
13371 this.fireEvent("specialkey", this, e);
13376 onResize: function(w, h){
13377 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13379 // if(typeof w != 'number'){
13380 // // we do not handle it!?!?
13383 // var tw = this.trigger.getWidth();
13384 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13385 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13387 // this.inputEl().setWidth( this.adjustWidth('input', x));
13389 // //this.trigger.setStyle('left', x+'px');
13391 // if(this.list && this.listWidth === undefined){
13392 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13393 // this.list.setWidth(lw);
13394 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13402 * Allow or prevent the user from directly editing the field text. If false is passed,
13403 * the user will only be able to select from the items defined in the dropdown list. This method
13404 * is the runtime equivalent of setting the 'editable' config option at config time.
13405 * @param {Boolean} value True to allow the user to directly edit the field text
13407 setEditable : function(value){
13408 if(value == this.editable){
13411 this.editable = value;
13413 this.inputEl().dom.setAttribute('readOnly', true);
13414 this.inputEl().on('mousedown', this.onTriggerClick, this);
13415 this.inputEl().addClass('x-combo-noedit');
13417 this.inputEl().dom.setAttribute('readOnly', false);
13418 this.inputEl().un('mousedown', this.onTriggerClick, this);
13419 this.inputEl().removeClass('x-combo-noedit');
13425 onBeforeLoad : function(combo,opts){
13426 if(!this.hasFocus){
13430 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13432 this.restrictHeight();
13433 this.selectedIndex = -1;
13437 onLoad : function(){
13439 this.hasQuery = false;
13441 if(!this.hasFocus){
13445 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13446 this.loading.hide();
13449 if(this.store.getCount() > 0){
13451 this.restrictHeight();
13452 if(this.lastQuery == this.allQuery){
13453 if(this.editable && !this.tickable){
13454 this.inputEl().dom.select();
13458 !this.selectByValue(this.value, true) &&
13461 !this.store.lastOptions ||
13462 typeof(this.store.lastOptions.add) == 'undefined' ||
13463 this.store.lastOptions.add != true
13466 this.select(0, true);
13469 if(this.autoFocus){
13472 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13473 this.taTask.delay(this.typeAheadDelay);
13477 this.onEmptyResults();
13483 onLoadException : function()
13485 this.hasQuery = false;
13487 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13488 this.loading.hide();
13491 if(this.tickable && this.editable){
13496 // only causes errors at present
13497 //Roo.log(this.store.reader.jsonData);
13498 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13500 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13506 onTypeAhead : function(){
13507 if(this.store.getCount() > 0){
13508 var r = this.store.getAt(0);
13509 var newValue = r.data[this.displayField];
13510 var len = newValue.length;
13511 var selStart = this.getRawValue().length;
13513 if(selStart != len){
13514 this.setRawValue(newValue);
13515 this.selectText(selStart, newValue.length);
13521 onSelect : function(record, index){
13523 if(this.fireEvent('beforeselect', this, record, index) !== false){
13525 this.setFromData(index > -1 ? record.data : false);
13528 this.fireEvent('select', this, record, index);
13533 * Returns the currently selected field value or empty string if no value is set.
13534 * @return {String} value The selected value
13536 getValue : function()
13538 if(Roo.isIOS && this.useNativeIOS){
13539 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13543 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13546 if(this.valueField){
13547 return typeof this.value != 'undefined' ? this.value : '';
13549 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13553 getRawValue : function()
13555 if(Roo.isIOS && this.useNativeIOS){
13556 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13559 var v = this.inputEl().getValue();
13565 * Clears any text/value currently set in the field
13567 clearValue : function(){
13569 if(this.hiddenField){
13570 this.hiddenField.dom.value = '';
13573 this.setRawValue('');
13574 this.lastSelectionText = '';
13575 this.lastData = false;
13577 var close = this.closeTriggerEl();
13588 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13589 * will be displayed in the field. If the value does not match the data value of an existing item,
13590 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13591 * Otherwise the field will be blank (although the value will still be set).
13592 * @param {String} value The value to match
13594 setValue : function(v)
13596 if(Roo.isIOS && this.useNativeIOS){
13597 this.setIOSValue(v);
13607 if(this.valueField){
13608 var r = this.findRecord(this.valueField, v);
13610 text = r.data[this.displayField];
13611 }else if(this.valueNotFoundText !== undefined){
13612 text = this.valueNotFoundText;
13615 this.lastSelectionText = text;
13616 if(this.hiddenField){
13617 this.hiddenField.dom.value = v;
13619 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13622 var close = this.closeTriggerEl();
13625 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13631 * @property {Object} the last set data for the element
13636 * Sets the value of the field based on a object which is related to the record format for the store.
13637 * @param {Object} value the value to set as. or false on reset?
13639 setFromData : function(o){
13646 var dv = ''; // display value
13647 var vv = ''; // value value..
13649 if (this.displayField) {
13650 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13652 // this is an error condition!!!
13653 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13656 if(this.valueField){
13657 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13660 var close = this.closeTriggerEl();
13663 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13666 if(this.hiddenField){
13667 this.hiddenField.dom.value = vv;
13669 this.lastSelectionText = dv;
13670 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13674 // no hidden field.. - we store the value in 'value', but still display
13675 // display field!!!!
13676 this.lastSelectionText = dv;
13677 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13684 reset : function(){
13685 // overridden so that last data is reset..
13692 this.setValue(this.originalValue);
13693 //this.clearInvalid();
13694 this.lastData = false;
13696 this.view.clearSelections();
13702 findRecord : function(prop, value){
13704 if(this.store.getCount() > 0){
13705 this.store.each(function(r){
13706 if(r.data[prop] == value){
13716 getName: function()
13718 // returns hidden if it's set..
13719 if (!this.rendered) {return ''};
13720 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13724 onViewMove : function(e, t){
13725 this.inKeyMode = false;
13729 onViewOver : function(e, t){
13730 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13733 var item = this.view.findItemFromChild(t);
13736 var index = this.view.indexOf(item);
13737 this.select(index, false);
13742 onViewClick : function(view, doFocus, el, e)
13744 var index = this.view.getSelectedIndexes()[0];
13746 var r = this.store.getAt(index);
13750 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13757 Roo.each(this.tickItems, function(v,k){
13759 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13761 _this.tickItems.splice(k, 1);
13763 if(typeof(e) == 'undefined' && view == false){
13764 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13776 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13777 this.tickItems.push(r.data);
13780 if(typeof(e) == 'undefined' && view == false){
13781 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13788 this.onSelect(r, index);
13790 if(doFocus !== false && !this.blockFocus){
13791 this.inputEl().focus();
13796 restrictHeight : function(){
13797 //this.innerList.dom.style.height = '';
13798 //var inner = this.innerList.dom;
13799 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13800 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13801 //this.list.beginUpdate();
13802 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13803 this.list.alignTo(this.inputEl(), this.listAlign);
13804 this.list.alignTo(this.inputEl(), this.listAlign);
13805 //this.list.endUpdate();
13809 onEmptyResults : function(){
13811 if(this.tickable && this.editable){
13812 this.restrictHeight();
13820 * Returns true if the dropdown list is expanded, else false.
13822 isExpanded : function(){
13823 return this.list.isVisible();
13827 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13828 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13829 * @param {String} value The data value of the item to select
13830 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13831 * selected item if it is not currently in view (defaults to true)
13832 * @return {Boolean} True if the value matched an item in the list, else false
13834 selectByValue : function(v, scrollIntoView){
13835 if(v !== undefined && v !== null){
13836 var r = this.findRecord(this.valueField || this.displayField, v);
13838 this.select(this.store.indexOf(r), scrollIntoView);
13846 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13847 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13848 * @param {Number} index The zero-based index of the list item to select
13849 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13850 * selected item if it is not currently in view (defaults to true)
13852 select : function(index, scrollIntoView){
13853 this.selectedIndex = index;
13854 this.view.select(index);
13855 if(scrollIntoView !== false){
13856 var el = this.view.getNode(index);
13858 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13861 this.list.scrollChildIntoView(el, false);
13867 selectNext : function(){
13868 var ct = this.store.getCount();
13870 if(this.selectedIndex == -1){
13872 }else if(this.selectedIndex < ct-1){
13873 this.select(this.selectedIndex+1);
13879 selectPrev : function(){
13880 var ct = this.store.getCount();
13882 if(this.selectedIndex == -1){
13884 }else if(this.selectedIndex != 0){
13885 this.select(this.selectedIndex-1);
13891 onKeyUp : function(e){
13892 if(this.editable !== false && !e.isSpecialKey()){
13893 this.lastKey = e.getKey();
13894 this.dqTask.delay(this.queryDelay);
13899 validateBlur : function(){
13900 return !this.list || !this.list.isVisible();
13904 initQuery : function(){
13906 var v = this.getRawValue();
13908 if(this.tickable && this.editable){
13909 v = this.tickableInputEl().getValue();
13916 doForce : function(){
13917 if(this.inputEl().dom.value.length > 0){
13918 this.inputEl().dom.value =
13919 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13925 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13926 * query allowing the query action to be canceled if needed.
13927 * @param {String} query The SQL query to execute
13928 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13929 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13930 * saved in the current store (defaults to false)
13932 doQuery : function(q, forceAll){
13934 if(q === undefined || q === null){
13939 forceAll: forceAll,
13943 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13948 forceAll = qe.forceAll;
13949 if(forceAll === true || (q.length >= this.minChars)){
13951 this.hasQuery = true;
13953 if(this.lastQuery != q || this.alwaysQuery){
13954 this.lastQuery = q;
13955 if(this.mode == 'local'){
13956 this.selectedIndex = -1;
13958 this.store.clearFilter();
13961 if(this.specialFilter){
13962 this.fireEvent('specialfilter', this);
13967 this.store.filter(this.displayField, q);
13970 this.store.fireEvent("datachanged", this.store);
13977 this.store.baseParams[this.queryParam] = q;
13979 var options = {params : this.getParams(q)};
13982 options.add = true;
13983 options.params.start = this.page * this.pageSize;
13986 this.store.load(options);
13989 * this code will make the page width larger, at the beginning, the list not align correctly,
13990 * we should expand the list on onLoad
13991 * so command out it
13996 this.selectedIndex = -1;
14001 this.loadNext = false;
14005 getParams : function(q){
14007 //p[this.queryParam] = q;
14011 p.limit = this.pageSize;
14017 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14019 collapse : function(){
14020 if(!this.isExpanded()){
14026 this.hasFocus = false;
14030 this.cancelBtn.hide();
14031 this.trigger.show();
14034 this.tickableInputEl().dom.value = '';
14035 this.tickableInputEl().blur();
14040 Roo.get(document).un('mousedown', this.collapseIf, this);
14041 Roo.get(document).un('mousewheel', this.collapseIf, this);
14042 if (!this.editable) {
14043 Roo.get(document).un('keydown', this.listKeyPress, this);
14045 this.fireEvent('collapse', this);
14051 collapseIf : function(e){
14052 var in_combo = e.within(this.el);
14053 var in_list = e.within(this.list);
14054 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14056 if (in_combo || in_list || is_list) {
14057 //e.stopPropagation();
14062 this.onTickableFooterButtonClick(e, false, false);
14070 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14072 expand : function(){
14074 if(this.isExpanded() || !this.hasFocus){
14078 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14079 this.list.setWidth(lw);
14085 this.restrictHeight();
14089 this.tickItems = Roo.apply([], this.item);
14092 this.cancelBtn.show();
14093 this.trigger.hide();
14096 this.tickableInputEl().focus();
14101 Roo.get(document).on('mousedown', this.collapseIf, this);
14102 Roo.get(document).on('mousewheel', this.collapseIf, this);
14103 if (!this.editable) {
14104 Roo.get(document).on('keydown', this.listKeyPress, this);
14107 this.fireEvent('expand', this);
14111 // Implements the default empty TriggerField.onTriggerClick function
14112 onTriggerClick : function(e)
14114 Roo.log('trigger click');
14116 if(this.disabled || !this.triggerList){
14121 this.loadNext = false;
14123 if(this.isExpanded()){
14125 if (!this.blockFocus) {
14126 this.inputEl().focus();
14130 this.hasFocus = true;
14131 if(this.triggerAction == 'all') {
14132 this.doQuery(this.allQuery, true);
14134 this.doQuery(this.getRawValue());
14136 if (!this.blockFocus) {
14137 this.inputEl().focus();
14142 onTickableTriggerClick : function(e)
14149 this.loadNext = false;
14150 this.hasFocus = true;
14152 if(this.triggerAction == 'all') {
14153 this.doQuery(this.allQuery, true);
14155 this.doQuery(this.getRawValue());
14159 onSearchFieldClick : function(e)
14161 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14162 this.onTickableFooterButtonClick(e, false, false);
14166 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14171 this.loadNext = false;
14172 this.hasFocus = true;
14174 if(this.triggerAction == 'all') {
14175 this.doQuery(this.allQuery, true);
14177 this.doQuery(this.getRawValue());
14181 listKeyPress : function(e)
14183 //Roo.log('listkeypress');
14184 // scroll to first matching element based on key pres..
14185 if (e.isSpecialKey()) {
14188 var k = String.fromCharCode(e.getKey()).toUpperCase();
14191 var csel = this.view.getSelectedNodes();
14192 var cselitem = false;
14194 var ix = this.view.indexOf(csel[0]);
14195 cselitem = this.store.getAt(ix);
14196 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14202 this.store.each(function(v) {
14204 // start at existing selection.
14205 if (cselitem.id == v.id) {
14211 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14212 match = this.store.indexOf(v);
14218 if (match === false) {
14219 return true; // no more action?
14222 this.view.select(match);
14223 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14224 sn.scrollIntoView(sn.dom.parentNode, false);
14227 onViewScroll : function(e, t){
14229 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){
14233 this.hasQuery = true;
14235 this.loading = this.list.select('.loading', true).first();
14237 if(this.loading === null){
14238 this.list.createChild({
14240 cls: 'loading roo-select2-more-results roo-select2-active',
14241 html: 'Loading more results...'
14244 this.loading = this.list.select('.loading', true).first();
14246 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14248 this.loading.hide();
14251 this.loading.show();
14256 this.loadNext = true;
14258 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14263 addItem : function(o)
14265 var dv = ''; // display value
14267 if (this.displayField) {
14268 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14270 // this is an error condition!!!
14271 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14278 var choice = this.choices.createChild({
14280 cls: 'roo-select2-search-choice',
14289 cls: 'roo-select2-search-choice-close',
14294 }, this.searchField);
14296 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14298 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14306 this.inputEl().dom.value = '';
14311 onRemoveItem : function(e, _self, o)
14313 e.preventDefault();
14315 this.lastItem = Roo.apply([], this.item);
14317 var index = this.item.indexOf(o.data) * 1;
14320 Roo.log('not this item?!');
14324 this.item.splice(index, 1);
14329 this.fireEvent('remove', this, e);
14335 syncValue : function()
14337 if(!this.item.length){
14344 Roo.each(this.item, function(i){
14345 if(_this.valueField){
14346 value.push(i[_this.valueField]);
14353 this.value = value.join(',');
14355 if(this.hiddenField){
14356 this.hiddenField.dom.value = this.value;
14359 this.store.fireEvent("datachanged", this.store);
14364 clearItem : function()
14366 if(!this.multiple){
14372 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14380 if(this.tickable && !Roo.isTouch){
14381 this.view.refresh();
14385 inputEl: function ()
14387 if(Roo.isIOS && this.useNativeIOS){
14388 return this.el.select('select.roo-ios-select', true).first();
14391 if(Roo.isTouch && this.mobileTouchView){
14392 return this.el.select('input.form-control',true).first();
14396 return this.searchField;
14399 return this.el.select('input.form-control',true).first();
14402 onTickableFooterButtonClick : function(e, btn, el)
14404 e.preventDefault();
14406 this.lastItem = Roo.apply([], this.item);
14408 if(btn && btn.name == 'cancel'){
14409 this.tickItems = Roo.apply([], this.item);
14418 Roo.each(this.tickItems, function(o){
14426 validate : function()
14428 var v = this.getRawValue();
14431 v = this.getValue();
14434 if(this.disabled || this.allowBlank || v.length){
14439 this.markInvalid();
14443 tickableInputEl : function()
14445 if(!this.tickable || !this.editable){
14446 return this.inputEl();
14449 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14453 getAutoCreateTouchView : function()
14458 cls: 'form-group' //input-group
14464 type : this.inputType,
14465 cls : 'form-control x-combo-noedit',
14466 autocomplete: 'new-password',
14467 placeholder : this.placeholder || '',
14472 input.name = this.name;
14476 input.cls += ' input-' + this.size;
14479 if (this.disabled) {
14480 input.disabled = true;
14491 inputblock.cls += ' input-group';
14493 inputblock.cn.unshift({
14495 cls : 'input-group-addon',
14500 if(this.removable && !this.multiple){
14501 inputblock.cls += ' roo-removable';
14503 inputblock.cn.push({
14506 cls : 'roo-combo-removable-btn close'
14510 if(this.hasFeedback && !this.allowBlank){
14512 inputblock.cls += ' has-feedback';
14514 inputblock.cn.push({
14516 cls: 'glyphicon form-control-feedback'
14523 inputblock.cls += (this.before) ? '' : ' input-group';
14525 inputblock.cn.push({
14527 cls : 'input-group-addon',
14538 cls: 'form-hidden-field'
14552 cls: 'form-hidden-field'
14556 cls: 'roo-select2-choices',
14560 cls: 'roo-select2-search-field',
14573 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14579 if(!this.multiple && this.showToggleBtn){
14586 if (this.caret != false) {
14589 cls: 'fa fa-' + this.caret
14596 cls : 'input-group-addon btn dropdown-toggle',
14601 cls: 'combobox-clear',
14615 combobox.cls += ' roo-select2-container-multi';
14618 var align = this.labelAlign || this.parentLabelAlign();
14620 if (align ==='left' && this.fieldLabel.length) {
14625 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14626 tooltip : 'This field is required'
14630 cls : 'control-label',
14631 html : this.fieldLabel
14642 var labelCfg = cfg.cn[1];
14643 var contentCfg = cfg.cn[2];
14646 if(this.indicatorpos == 'right'){
14650 cls : 'control-label',
14651 html : this.fieldLabel,
14655 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14656 tooltip : 'This field is required'
14669 labelCfg = cfg.cn[0];
14670 contentCfg = cfg.cn[2];
14672 if(this.labelWidth > 12){
14673 labelCfg.style = "width: " + this.labelWidth + 'px';
14676 if(this.labelWidth < 13 && this.labelmd == 0){
14677 this.labelmd = this.labelWidth;
14680 if(this.labellg > 0){
14681 labelCfg.cls += ' col-lg-' + this.labellg;
14682 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14685 if(this.labelmd > 0){
14686 labelCfg.cls += ' col-md-' + this.labelmd;
14687 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14690 if(this.labelsm > 0){
14691 labelCfg.cls += ' col-sm-' + this.labelsm;
14692 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14695 if(this.labelxs > 0){
14696 labelCfg.cls += ' col-xs-' + this.labelxs;
14697 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14701 } else if ( this.fieldLabel.length) {
14705 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14706 tooltip : 'This field is required'
14710 cls : 'control-label',
14711 html : this.fieldLabel
14722 if(this.indicatorpos == 'right'){
14726 cls : 'control-label',
14727 html : this.fieldLabel,
14731 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14732 tooltip : 'This field is required'
14749 var settings = this;
14751 ['xs','sm','md','lg'].map(function(size){
14752 if (settings[size]) {
14753 cfg.cls += ' col-' + size + '-' + settings[size];
14760 initTouchView : function()
14762 this.renderTouchView();
14764 this.touchViewEl.on('scroll', function(){
14765 this.el.dom.scrollTop = 0;
14768 this.originalValue = this.getValue();
14770 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14772 this.inputEl().on("click", this.showTouchView, this);
14773 if (this.triggerEl) {
14774 this.triggerEl.on("click", this.showTouchView, this);
14778 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14779 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14781 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14783 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14784 this.store.on('load', this.onTouchViewLoad, this);
14785 this.store.on('loadexception', this.onTouchViewLoadException, this);
14787 if(this.hiddenName){
14789 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14791 this.hiddenField.dom.value =
14792 this.hiddenValue !== undefined ? this.hiddenValue :
14793 this.value !== undefined ? this.value : '';
14795 this.el.dom.removeAttribute('name');
14796 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14800 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14801 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14804 if(this.removable && !this.multiple){
14805 var close = this.closeTriggerEl();
14807 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14808 close.on('click', this.removeBtnClick, this, close);
14812 * fix the bug in Safari iOS8
14814 this.inputEl().on("focus", function(e){
14815 document.activeElement.blur();
14823 renderTouchView : function()
14825 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14826 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14828 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14829 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14831 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14832 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14833 this.touchViewBodyEl.setStyle('overflow', 'auto');
14835 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14836 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14838 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14839 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14843 showTouchView : function()
14849 this.touchViewHeaderEl.hide();
14851 if(this.modalTitle.length){
14852 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14853 this.touchViewHeaderEl.show();
14856 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14857 this.touchViewEl.show();
14859 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14860 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14861 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14863 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14865 if(this.modalTitle.length){
14866 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14869 this.touchViewBodyEl.setHeight(bodyHeight);
14873 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14875 this.touchViewEl.addClass('in');
14878 this.doTouchViewQuery();
14882 hideTouchView : function()
14884 this.touchViewEl.removeClass('in');
14888 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14890 this.touchViewEl.setStyle('display', 'none');
14895 setTouchViewValue : function()
14902 Roo.each(this.tickItems, function(o){
14907 this.hideTouchView();
14910 doTouchViewQuery : function()
14919 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14923 if(!this.alwaysQuery || this.mode == 'local'){
14924 this.onTouchViewLoad();
14931 onTouchViewBeforeLoad : function(combo,opts)
14937 onTouchViewLoad : function()
14939 if(this.store.getCount() < 1){
14940 this.onTouchViewEmptyResults();
14944 this.clearTouchView();
14946 var rawValue = this.getRawValue();
14948 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14950 this.tickItems = [];
14952 this.store.data.each(function(d, rowIndex){
14953 var row = this.touchViewListGroup.createChild(template);
14955 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14956 row.addClass(d.data.cls);
14959 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14962 html : d.data[this.displayField]
14965 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14966 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14969 row.removeClass('selected');
14970 if(!this.multiple && this.valueField &&
14971 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14974 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14975 row.addClass('selected');
14978 if(this.multiple && this.valueField &&
14979 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14983 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14984 this.tickItems.push(d.data);
14987 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14991 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14993 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14995 if(this.modalTitle.length){
14996 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14999 var listHeight = this.touchViewListGroup.getHeight();
15003 if(firstChecked && listHeight > bodyHeight){
15004 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15009 onTouchViewLoadException : function()
15011 this.hideTouchView();
15014 onTouchViewEmptyResults : function()
15016 this.clearTouchView();
15018 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15020 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15024 clearTouchView : function()
15026 this.touchViewListGroup.dom.innerHTML = '';
15029 onTouchViewClick : function(e, el, o)
15031 e.preventDefault();
15034 var rowIndex = o.rowIndex;
15036 var r = this.store.getAt(rowIndex);
15038 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15040 if(!this.multiple){
15041 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15042 c.dom.removeAttribute('checked');
15045 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15047 this.setFromData(r.data);
15049 var close = this.closeTriggerEl();
15055 this.hideTouchView();
15057 this.fireEvent('select', this, r, rowIndex);
15062 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15063 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15064 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15068 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15069 this.addItem(r.data);
15070 this.tickItems.push(r.data);
15074 getAutoCreateNativeIOS : function()
15077 cls: 'form-group' //input-group,
15082 cls : 'roo-ios-select'
15086 combobox.name = this.name;
15089 if (this.disabled) {
15090 combobox.disabled = true;
15093 var settings = this;
15095 ['xs','sm','md','lg'].map(function(size){
15096 if (settings[size]) {
15097 cfg.cls += ' col-' + size + '-' + settings[size];
15107 initIOSView : function()
15109 this.store.on('load', this.onIOSViewLoad, this);
15114 onIOSViewLoad : function()
15116 if(this.store.getCount() < 1){
15120 this.clearIOSView();
15122 if(this.allowBlank) {
15124 var default_text = '-- SELECT --';
15126 var opt = this.inputEl().createChild({
15129 html : default_text
15133 o[this.valueField] = 0;
15134 o[this.displayField] = default_text;
15136 this.ios_options.push({
15143 this.store.data.each(function(d, rowIndex){
15147 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15148 html = d.data[this.displayField];
15153 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15154 value = d.data[this.valueField];
15163 if(this.value == d.data[this.valueField]){
15164 option['selected'] = true;
15167 var opt = this.inputEl().createChild(option);
15169 this.ios_options.push({
15176 this.inputEl().on('change', function(){
15177 this.fireEvent('select', this);
15182 clearIOSView: function()
15184 this.inputEl().dom.innerHTML = '';
15186 this.ios_options = [];
15189 setIOSValue: function(v)
15193 if(!this.ios_options){
15197 Roo.each(this.ios_options, function(opts){
15199 opts.el.dom.removeAttribute('selected');
15201 if(opts.data[this.valueField] != v){
15205 opts.el.dom.setAttribute('selected', true);
15211 * @cfg {Boolean} grow
15215 * @cfg {Number} growMin
15219 * @cfg {Number} growMax
15228 Roo.apply(Roo.bootstrap.ComboBox, {
15232 cls: 'modal-header',
15254 cls: 'list-group-item',
15258 cls: 'roo-combobox-list-group-item-value'
15262 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15276 listItemCheckbox : {
15278 cls: 'list-group-item',
15282 cls: 'roo-combobox-list-group-item-value'
15286 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15302 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15307 cls: 'modal-footer',
15315 cls: 'col-xs-6 text-left',
15318 cls: 'btn btn-danger roo-touch-view-cancel',
15324 cls: 'col-xs-6 text-right',
15327 cls: 'btn btn-success roo-touch-view-ok',
15338 Roo.apply(Roo.bootstrap.ComboBox, {
15340 touchViewTemplate : {
15342 cls: 'modal fade roo-combobox-touch-view',
15346 cls: 'modal-dialog',
15347 style : 'position:fixed', // we have to fix position....
15351 cls: 'modal-content',
15353 Roo.bootstrap.ComboBox.header,
15354 Roo.bootstrap.ComboBox.body,
15355 Roo.bootstrap.ComboBox.footer
15364 * Ext JS Library 1.1.1
15365 * Copyright(c) 2006-2007, Ext JS, LLC.
15367 * Originally Released Under LGPL - original licence link has changed is not relivant.
15370 * <script type="text/javascript">
15375 * @extends Roo.util.Observable
15376 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15377 * This class also supports single and multi selection modes. <br>
15378 * Create a data model bound view:
15380 var store = new Roo.data.Store(...);
15382 var view = new Roo.View({
15384 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15386 singleSelect: true,
15387 selectedClass: "ydataview-selected",
15391 // listen for node click?
15392 view.on("click", function(vw, index, node, e){
15393 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15397 dataModel.load("foobar.xml");
15399 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15401 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15402 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15404 * Note: old style constructor is still suported (container, template, config)
15407 * Create a new View
15408 * @param {Object} config The config object
15411 Roo.View = function(config, depreciated_tpl, depreciated_config){
15413 this.parent = false;
15415 if (typeof(depreciated_tpl) == 'undefined') {
15416 // new way.. - universal constructor.
15417 Roo.apply(this, config);
15418 this.el = Roo.get(this.el);
15421 this.el = Roo.get(config);
15422 this.tpl = depreciated_tpl;
15423 Roo.apply(this, depreciated_config);
15425 this.wrapEl = this.el.wrap().wrap();
15426 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15429 if(typeof(this.tpl) == "string"){
15430 this.tpl = new Roo.Template(this.tpl);
15432 // support xtype ctors..
15433 this.tpl = new Roo.factory(this.tpl, Roo);
15437 this.tpl.compile();
15442 * @event beforeclick
15443 * Fires before a click is processed. Returns false to cancel the default action.
15444 * @param {Roo.View} this
15445 * @param {Number} index The index of the target node
15446 * @param {HTMLElement} node The target node
15447 * @param {Roo.EventObject} e The raw event object
15449 "beforeclick" : true,
15452 * Fires when a template node is clicked.
15453 * @param {Roo.View} this
15454 * @param {Number} index The index of the target node
15455 * @param {HTMLElement} node The target node
15456 * @param {Roo.EventObject} e The raw event object
15461 * Fires when a template node is double clicked.
15462 * @param {Roo.View} this
15463 * @param {Number} index The index of the target node
15464 * @param {HTMLElement} node The target node
15465 * @param {Roo.EventObject} e The raw event object
15469 * @event contextmenu
15470 * Fires when a template node is right clicked.
15471 * @param {Roo.View} this
15472 * @param {Number} index The index of the target node
15473 * @param {HTMLElement} node The target node
15474 * @param {Roo.EventObject} e The raw event object
15476 "contextmenu" : true,
15478 * @event selectionchange
15479 * Fires when the selected nodes change.
15480 * @param {Roo.View} this
15481 * @param {Array} selections Array of the selected nodes
15483 "selectionchange" : true,
15486 * @event beforeselect
15487 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15488 * @param {Roo.View} this
15489 * @param {HTMLElement} node The node to be selected
15490 * @param {Array} selections Array of currently selected nodes
15492 "beforeselect" : true,
15494 * @event preparedata
15495 * Fires on every row to render, to allow you to change the data.
15496 * @param {Roo.View} this
15497 * @param {Object} data to be rendered (change this)
15499 "preparedata" : true
15507 "click": this.onClick,
15508 "dblclick": this.onDblClick,
15509 "contextmenu": this.onContextMenu,
15513 this.selections = [];
15515 this.cmp = new Roo.CompositeElementLite([]);
15517 this.store = Roo.factory(this.store, Roo.data);
15518 this.setStore(this.store, true);
15521 if ( this.footer && this.footer.xtype) {
15523 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15525 this.footer.dataSource = this.store;
15526 this.footer.container = fctr;
15527 this.footer = Roo.factory(this.footer, Roo);
15528 fctr.insertFirst(this.el);
15530 // this is a bit insane - as the paging toolbar seems to detach the el..
15531 // dom.parentNode.parentNode.parentNode
15532 // they get detached?
15536 Roo.View.superclass.constructor.call(this);
15541 Roo.extend(Roo.View, Roo.util.Observable, {
15544 * @cfg {Roo.data.Store} store Data store to load data from.
15549 * @cfg {String|Roo.Element} el The container element.
15554 * @cfg {String|Roo.Template} tpl The template used by this View
15558 * @cfg {String} dataName the named area of the template to use as the data area
15559 * Works with domtemplates roo-name="name"
15563 * @cfg {String} selectedClass The css class to add to selected nodes
15565 selectedClass : "x-view-selected",
15567 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15572 * @cfg {String} text to display on mask (default Loading)
15576 * @cfg {Boolean} multiSelect Allow multiple selection
15578 multiSelect : false,
15580 * @cfg {Boolean} singleSelect Allow single selection
15582 singleSelect: false,
15585 * @cfg {Boolean} toggleSelect - selecting
15587 toggleSelect : false,
15590 * @cfg {Boolean} tickable - selecting
15595 * Returns the element this view is bound to.
15596 * @return {Roo.Element}
15598 getEl : function(){
15599 return this.wrapEl;
15605 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15607 refresh : function(){
15608 //Roo.log('refresh');
15611 // if we are using something like 'domtemplate', then
15612 // the what gets used is:
15613 // t.applySubtemplate(NAME, data, wrapping data..)
15614 // the outer template then get' applied with
15615 // the store 'extra data'
15616 // and the body get's added to the
15617 // roo-name="data" node?
15618 // <span class='roo-tpl-{name}'></span> ?????
15622 this.clearSelections();
15623 this.el.update("");
15625 var records = this.store.getRange();
15626 if(records.length < 1) {
15628 // is this valid?? = should it render a template??
15630 this.el.update(this.emptyText);
15634 if (this.dataName) {
15635 this.el.update(t.apply(this.store.meta)); //????
15636 el = this.el.child('.roo-tpl-' + this.dataName);
15639 for(var i = 0, len = records.length; i < len; i++){
15640 var data = this.prepareData(records[i].data, i, records[i]);
15641 this.fireEvent("preparedata", this, data, i, records[i]);
15643 var d = Roo.apply({}, data);
15646 Roo.apply(d, {'roo-id' : Roo.id()});
15650 Roo.each(this.parent.item, function(item){
15651 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15654 Roo.apply(d, {'roo-data-checked' : 'checked'});
15658 html[html.length] = Roo.util.Format.trim(
15660 t.applySubtemplate(this.dataName, d, this.store.meta) :
15667 el.update(html.join(""));
15668 this.nodes = el.dom.childNodes;
15669 this.updateIndexes(0);
15674 * Function to override to reformat the data that is sent to
15675 * the template for each node.
15676 * DEPRICATED - use the preparedata event handler.
15677 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15678 * a JSON object for an UpdateManager bound view).
15680 prepareData : function(data, index, record)
15682 this.fireEvent("preparedata", this, data, index, record);
15686 onUpdate : function(ds, record){
15687 // Roo.log('on update');
15688 this.clearSelections();
15689 var index = this.store.indexOf(record);
15690 var n = this.nodes[index];
15691 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15692 n.parentNode.removeChild(n);
15693 this.updateIndexes(index, index);
15699 onAdd : function(ds, records, index)
15701 //Roo.log(['on Add', ds, records, index] );
15702 this.clearSelections();
15703 if(this.nodes.length == 0){
15707 var n = this.nodes[index];
15708 for(var i = 0, len = records.length; i < len; i++){
15709 var d = this.prepareData(records[i].data, i, records[i]);
15711 this.tpl.insertBefore(n, d);
15714 this.tpl.append(this.el, d);
15717 this.updateIndexes(index);
15720 onRemove : function(ds, record, index){
15721 // Roo.log('onRemove');
15722 this.clearSelections();
15723 var el = this.dataName ?
15724 this.el.child('.roo-tpl-' + this.dataName) :
15727 el.dom.removeChild(this.nodes[index]);
15728 this.updateIndexes(index);
15732 * Refresh an individual node.
15733 * @param {Number} index
15735 refreshNode : function(index){
15736 this.onUpdate(this.store, this.store.getAt(index));
15739 updateIndexes : function(startIndex, endIndex){
15740 var ns = this.nodes;
15741 startIndex = startIndex || 0;
15742 endIndex = endIndex || ns.length - 1;
15743 for(var i = startIndex; i <= endIndex; i++){
15744 ns[i].nodeIndex = i;
15749 * Changes the data store this view uses and refresh the view.
15750 * @param {Store} store
15752 setStore : function(store, initial){
15753 if(!initial && this.store){
15754 this.store.un("datachanged", this.refresh);
15755 this.store.un("add", this.onAdd);
15756 this.store.un("remove", this.onRemove);
15757 this.store.un("update", this.onUpdate);
15758 this.store.un("clear", this.refresh);
15759 this.store.un("beforeload", this.onBeforeLoad);
15760 this.store.un("load", this.onLoad);
15761 this.store.un("loadexception", this.onLoad);
15765 store.on("datachanged", this.refresh, this);
15766 store.on("add", this.onAdd, this);
15767 store.on("remove", this.onRemove, this);
15768 store.on("update", this.onUpdate, this);
15769 store.on("clear", this.refresh, this);
15770 store.on("beforeload", this.onBeforeLoad, this);
15771 store.on("load", this.onLoad, this);
15772 store.on("loadexception", this.onLoad, this);
15780 * onbeforeLoad - masks the loading area.
15783 onBeforeLoad : function(store,opts)
15785 //Roo.log('onBeforeLoad');
15787 this.el.update("");
15789 this.el.mask(this.mask ? this.mask : "Loading" );
15791 onLoad : function ()
15798 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15799 * @param {HTMLElement} node
15800 * @return {HTMLElement} The template node
15802 findItemFromChild : function(node){
15803 var el = this.dataName ?
15804 this.el.child('.roo-tpl-' + this.dataName,true) :
15807 if(!node || node.parentNode == el){
15810 var p = node.parentNode;
15811 while(p && p != el){
15812 if(p.parentNode == el){
15821 onClick : function(e){
15822 var item = this.findItemFromChild(e.getTarget());
15824 var index = this.indexOf(item);
15825 if(this.onItemClick(item, index, e) !== false){
15826 this.fireEvent("click", this, index, item, e);
15829 this.clearSelections();
15834 onContextMenu : function(e){
15835 var item = this.findItemFromChild(e.getTarget());
15837 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15842 onDblClick : function(e){
15843 var item = this.findItemFromChild(e.getTarget());
15845 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15849 onItemClick : function(item, index, e)
15851 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15854 if (this.toggleSelect) {
15855 var m = this.isSelected(item) ? 'unselect' : 'select';
15858 _t[m](item, true, false);
15861 if(this.multiSelect || this.singleSelect){
15862 if(this.multiSelect && e.shiftKey && this.lastSelection){
15863 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15865 this.select(item, this.multiSelect && e.ctrlKey);
15866 this.lastSelection = item;
15869 if(!this.tickable){
15870 e.preventDefault();
15878 * Get the number of selected nodes.
15881 getSelectionCount : function(){
15882 return this.selections.length;
15886 * Get the currently selected nodes.
15887 * @return {Array} An array of HTMLElements
15889 getSelectedNodes : function(){
15890 return this.selections;
15894 * Get the indexes of the selected nodes.
15897 getSelectedIndexes : function(){
15898 var indexes = [], s = this.selections;
15899 for(var i = 0, len = s.length; i < len; i++){
15900 indexes.push(s[i].nodeIndex);
15906 * Clear all selections
15907 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15909 clearSelections : function(suppressEvent){
15910 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15911 this.cmp.elements = this.selections;
15912 this.cmp.removeClass(this.selectedClass);
15913 this.selections = [];
15914 if(!suppressEvent){
15915 this.fireEvent("selectionchange", this, this.selections);
15921 * Returns true if the passed node is selected
15922 * @param {HTMLElement/Number} node The node or node index
15923 * @return {Boolean}
15925 isSelected : function(node){
15926 var s = this.selections;
15930 node = this.getNode(node);
15931 return s.indexOf(node) !== -1;
15936 * @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
15937 * @param {Boolean} keepExisting (optional) true to keep existing selections
15938 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15940 select : function(nodeInfo, keepExisting, suppressEvent){
15941 if(nodeInfo instanceof Array){
15943 this.clearSelections(true);
15945 for(var i = 0, len = nodeInfo.length; i < len; i++){
15946 this.select(nodeInfo[i], true, true);
15950 var node = this.getNode(nodeInfo);
15951 if(!node || this.isSelected(node)){
15952 return; // already selected.
15955 this.clearSelections(true);
15958 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15959 Roo.fly(node).addClass(this.selectedClass);
15960 this.selections.push(node);
15961 if(!suppressEvent){
15962 this.fireEvent("selectionchange", this, this.selections);
15970 * @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
15971 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15972 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15974 unselect : function(nodeInfo, keepExisting, suppressEvent)
15976 if(nodeInfo instanceof Array){
15977 Roo.each(this.selections, function(s) {
15978 this.unselect(s, nodeInfo);
15982 var node = this.getNode(nodeInfo);
15983 if(!node || !this.isSelected(node)){
15984 //Roo.log("not selected");
15985 return; // not selected.
15989 Roo.each(this.selections, function(s) {
15991 Roo.fly(node).removeClass(this.selectedClass);
15998 this.selections= ns;
15999 this.fireEvent("selectionchange", this, this.selections);
16003 * Gets a template node.
16004 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16005 * @return {HTMLElement} The node or null if it wasn't found
16007 getNode : function(nodeInfo){
16008 if(typeof nodeInfo == "string"){
16009 return document.getElementById(nodeInfo);
16010 }else if(typeof nodeInfo == "number"){
16011 return this.nodes[nodeInfo];
16017 * Gets a range template nodes.
16018 * @param {Number} startIndex
16019 * @param {Number} endIndex
16020 * @return {Array} An array of nodes
16022 getNodes : function(start, end){
16023 var ns = this.nodes;
16024 start = start || 0;
16025 end = typeof end == "undefined" ? ns.length - 1 : end;
16028 for(var i = start; i <= end; i++){
16032 for(var i = start; i >= end; i--){
16040 * Finds the index of the passed node
16041 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16042 * @return {Number} The index of the node or -1
16044 indexOf : function(node){
16045 node = this.getNode(node);
16046 if(typeof node.nodeIndex == "number"){
16047 return node.nodeIndex;
16049 var ns = this.nodes;
16050 for(var i = 0, len = ns.length; i < len; i++){
16061 * based on jquery fullcalendar
16065 Roo.bootstrap = Roo.bootstrap || {};
16067 * @class Roo.bootstrap.Calendar
16068 * @extends Roo.bootstrap.Component
16069 * Bootstrap Calendar class
16070 * @cfg {Boolean} loadMask (true|false) default false
16071 * @cfg {Object} header generate the user specific header of the calendar, default false
16074 * Create a new Container
16075 * @param {Object} config The config object
16080 Roo.bootstrap.Calendar = function(config){
16081 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16085 * Fires when a date is selected
16086 * @param {DatePicker} this
16087 * @param {Date} date The selected date
16091 * @event monthchange
16092 * Fires when the displayed month changes
16093 * @param {DatePicker} this
16094 * @param {Date} date The selected month
16096 'monthchange': true,
16098 * @event evententer
16099 * Fires when mouse over an event
16100 * @param {Calendar} this
16101 * @param {event} Event
16103 'evententer': true,
16105 * @event eventleave
16106 * Fires when the mouse leaves an
16107 * @param {Calendar} this
16110 'eventleave': true,
16112 * @event eventclick
16113 * Fires when the mouse click an
16114 * @param {Calendar} this
16123 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16126 * @cfg {Number} startDay
16127 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16135 getAutoCreate : function(){
16138 var fc_button = function(name, corner, style, content ) {
16139 return Roo.apply({},{
16141 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16143 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16146 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16157 style : 'width:100%',
16164 cls : 'fc-header-left',
16166 fc_button('prev', 'left', 'arrow', '‹' ),
16167 fc_button('next', 'right', 'arrow', '›' ),
16168 { tag: 'span', cls: 'fc-header-space' },
16169 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16177 cls : 'fc-header-center',
16181 cls: 'fc-header-title',
16184 html : 'month / year'
16192 cls : 'fc-header-right',
16194 /* fc_button('month', 'left', '', 'month' ),
16195 fc_button('week', '', '', 'week' ),
16196 fc_button('day', 'right', '', 'day' )
16208 header = this.header;
16211 var cal_heads = function() {
16213 // fixme - handle this.
16215 for (var i =0; i < Date.dayNames.length; i++) {
16216 var d = Date.dayNames[i];
16219 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16220 html : d.substring(0,3)
16224 ret[0].cls += ' fc-first';
16225 ret[6].cls += ' fc-last';
16228 var cal_cell = function(n) {
16231 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16236 cls: 'fc-day-number',
16240 cls: 'fc-day-content',
16244 style: 'position: relative;' // height: 17px;
16256 var cal_rows = function() {
16259 for (var r = 0; r < 6; r++) {
16266 for (var i =0; i < Date.dayNames.length; i++) {
16267 var d = Date.dayNames[i];
16268 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16271 row.cn[0].cls+=' fc-first';
16272 row.cn[0].cn[0].style = 'min-height:90px';
16273 row.cn[6].cls+=' fc-last';
16277 ret[0].cls += ' fc-first';
16278 ret[4].cls += ' fc-prev-last';
16279 ret[5].cls += ' fc-last';
16286 cls: 'fc-border-separate',
16287 style : 'width:100%',
16295 cls : 'fc-first fc-last',
16313 cls : 'fc-content',
16314 style : "position: relative;",
16317 cls : 'fc-view fc-view-month fc-grid',
16318 style : 'position: relative',
16319 unselectable : 'on',
16322 cls : 'fc-event-container',
16323 style : 'position:absolute;z-index:8;top:0;left:0;'
16341 initEvents : function()
16344 throw "can not find store for calendar";
16350 style: "text-align:center",
16354 style: "background-color:white;width:50%;margin:250 auto",
16358 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16369 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16371 var size = this.el.select('.fc-content', true).first().getSize();
16372 this.maskEl.setSize(size.width, size.height);
16373 this.maskEl.enableDisplayMode("block");
16374 if(!this.loadMask){
16375 this.maskEl.hide();
16378 this.store = Roo.factory(this.store, Roo.data);
16379 this.store.on('load', this.onLoad, this);
16380 this.store.on('beforeload', this.onBeforeLoad, this);
16384 this.cells = this.el.select('.fc-day',true);
16385 //Roo.log(this.cells);
16386 this.textNodes = this.el.query('.fc-day-number');
16387 this.cells.addClassOnOver('fc-state-hover');
16389 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16390 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16391 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16392 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16394 this.on('monthchange', this.onMonthChange, this);
16396 this.update(new Date().clearTime());
16399 resize : function() {
16400 var sz = this.el.getSize();
16402 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16403 this.el.select('.fc-day-content div',true).setHeight(34);
16408 showPrevMonth : function(e){
16409 this.update(this.activeDate.add("mo", -1));
16411 showToday : function(e){
16412 this.update(new Date().clearTime());
16415 showNextMonth : function(e){
16416 this.update(this.activeDate.add("mo", 1));
16420 showPrevYear : function(){
16421 this.update(this.activeDate.add("y", -1));
16425 showNextYear : function(){
16426 this.update(this.activeDate.add("y", 1));
16431 update : function(date)
16433 var vd = this.activeDate;
16434 this.activeDate = date;
16435 // if(vd && this.el){
16436 // var t = date.getTime();
16437 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16438 // Roo.log('using add remove');
16440 // this.fireEvent('monthchange', this, date);
16442 // this.cells.removeClass("fc-state-highlight");
16443 // this.cells.each(function(c){
16444 // if(c.dateValue == t){
16445 // c.addClass("fc-state-highlight");
16446 // setTimeout(function(){
16447 // try{c.dom.firstChild.focus();}catch(e){}
16457 var days = date.getDaysInMonth();
16459 var firstOfMonth = date.getFirstDateOfMonth();
16460 var startingPos = firstOfMonth.getDay()-this.startDay;
16462 if(startingPos < this.startDay){
16466 var pm = date.add(Date.MONTH, -1);
16467 var prevStart = pm.getDaysInMonth()-startingPos;
16469 this.cells = this.el.select('.fc-day',true);
16470 this.textNodes = this.el.query('.fc-day-number');
16471 this.cells.addClassOnOver('fc-state-hover');
16473 var cells = this.cells.elements;
16474 var textEls = this.textNodes;
16476 Roo.each(cells, function(cell){
16477 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16480 days += startingPos;
16482 // convert everything to numbers so it's fast
16483 var day = 86400000;
16484 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16487 //Roo.log(prevStart);
16489 var today = new Date().clearTime().getTime();
16490 var sel = date.clearTime().getTime();
16491 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16492 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16493 var ddMatch = this.disabledDatesRE;
16494 var ddText = this.disabledDatesText;
16495 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16496 var ddaysText = this.disabledDaysText;
16497 var format = this.format;
16499 var setCellClass = function(cal, cell){
16503 //Roo.log('set Cell Class');
16505 var t = d.getTime();
16509 cell.dateValue = t;
16511 cell.className += " fc-today";
16512 cell.className += " fc-state-highlight";
16513 cell.title = cal.todayText;
16516 // disable highlight in other month..
16517 //cell.className += " fc-state-highlight";
16522 cell.className = " fc-state-disabled";
16523 cell.title = cal.minText;
16527 cell.className = " fc-state-disabled";
16528 cell.title = cal.maxText;
16532 if(ddays.indexOf(d.getDay()) != -1){
16533 cell.title = ddaysText;
16534 cell.className = " fc-state-disabled";
16537 if(ddMatch && format){
16538 var fvalue = d.dateFormat(format);
16539 if(ddMatch.test(fvalue)){
16540 cell.title = ddText.replace("%0", fvalue);
16541 cell.className = " fc-state-disabled";
16545 if (!cell.initialClassName) {
16546 cell.initialClassName = cell.dom.className;
16549 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16554 for(; i < startingPos; i++) {
16555 textEls[i].innerHTML = (++prevStart);
16556 d.setDate(d.getDate()+1);
16558 cells[i].className = "fc-past fc-other-month";
16559 setCellClass(this, cells[i]);
16564 for(; i < days; i++){
16565 intDay = i - startingPos + 1;
16566 textEls[i].innerHTML = (intDay);
16567 d.setDate(d.getDate()+1);
16569 cells[i].className = ''; // "x-date-active";
16570 setCellClass(this, cells[i]);
16574 for(; i < 42; i++) {
16575 textEls[i].innerHTML = (++extraDays);
16576 d.setDate(d.getDate()+1);
16578 cells[i].className = "fc-future fc-other-month";
16579 setCellClass(this, cells[i]);
16582 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16584 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16586 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16587 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16589 if(totalRows != 6){
16590 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16591 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16594 this.fireEvent('monthchange', this, date);
16598 if(!this.internalRender){
16599 var main = this.el.dom.firstChild;
16600 var w = main.offsetWidth;
16601 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16602 Roo.fly(main).setWidth(w);
16603 this.internalRender = true;
16604 // opera does not respect the auto grow header center column
16605 // then, after it gets a width opera refuses to recalculate
16606 // without a second pass
16607 if(Roo.isOpera && !this.secondPass){
16608 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16609 this.secondPass = true;
16610 this.update.defer(10, this, [date]);
16617 findCell : function(dt) {
16618 dt = dt.clearTime().getTime();
16620 this.cells.each(function(c){
16621 //Roo.log("check " +c.dateValue + '?=' + dt);
16622 if(c.dateValue == dt){
16632 findCells : function(ev) {
16633 var s = ev.start.clone().clearTime().getTime();
16635 var e= ev.end.clone().clearTime().getTime();
16638 this.cells.each(function(c){
16639 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16641 if(c.dateValue > e){
16644 if(c.dateValue < s){
16653 // findBestRow: function(cells)
16657 // for (var i =0 ; i < cells.length;i++) {
16658 // ret = Math.max(cells[i].rows || 0,ret);
16665 addItem : function(ev)
16667 // look for vertical location slot in
16668 var cells = this.findCells(ev);
16670 // ev.row = this.findBestRow(cells);
16672 // work out the location.
16676 for(var i =0; i < cells.length; i++) {
16678 cells[i].row = cells[0].row;
16681 cells[i].row = cells[i].row + 1;
16691 if (crow.start.getY() == cells[i].getY()) {
16693 crow.end = cells[i];
16710 cells[0].events.push(ev);
16712 this.calevents.push(ev);
16715 clearEvents: function() {
16717 if(!this.calevents){
16721 Roo.each(this.cells.elements, function(c){
16727 Roo.each(this.calevents, function(e) {
16728 Roo.each(e.els, function(el) {
16729 el.un('mouseenter' ,this.onEventEnter, this);
16730 el.un('mouseleave' ,this.onEventLeave, this);
16735 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16741 renderEvents: function()
16745 this.cells.each(function(c) {
16754 if(c.row != c.events.length){
16755 r = 4 - (4 - (c.row - c.events.length));
16758 c.events = ev.slice(0, r);
16759 c.more = ev.slice(r);
16761 if(c.more.length && c.more.length == 1){
16762 c.events.push(c.more.pop());
16765 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16769 this.cells.each(function(c) {
16771 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16774 for (var e = 0; e < c.events.length; e++){
16775 var ev = c.events[e];
16776 var rows = ev.rows;
16778 for(var i = 0; i < rows.length; i++) {
16780 // how many rows should it span..
16783 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16784 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16786 unselectable : "on",
16789 cls: 'fc-event-inner',
16793 // cls: 'fc-event-time',
16794 // html : cells.length > 1 ? '' : ev.time
16798 cls: 'fc-event-title',
16799 html : String.format('{0}', ev.title)
16806 cls: 'ui-resizable-handle ui-resizable-e',
16807 html : '  '
16814 cfg.cls += ' fc-event-start';
16816 if ((i+1) == rows.length) {
16817 cfg.cls += ' fc-event-end';
16820 var ctr = _this.el.select('.fc-event-container',true).first();
16821 var cg = ctr.createChild(cfg);
16823 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16824 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16826 var r = (c.more.length) ? 1 : 0;
16827 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16828 cg.setWidth(ebox.right - sbox.x -2);
16830 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16831 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16832 cg.on('click', _this.onEventClick, _this, ev);
16843 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16844 style : 'position: absolute',
16845 unselectable : "on",
16848 cls: 'fc-event-inner',
16852 cls: 'fc-event-title',
16860 cls: 'ui-resizable-handle ui-resizable-e',
16861 html : '  '
16867 var ctr = _this.el.select('.fc-event-container',true).first();
16868 var cg = ctr.createChild(cfg);
16870 var sbox = c.select('.fc-day-content',true).first().getBox();
16871 var ebox = c.select('.fc-day-content',true).first().getBox();
16873 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16874 cg.setWidth(ebox.right - sbox.x -2);
16876 cg.on('click', _this.onMoreEventClick, _this, c.more);
16886 onEventEnter: function (e, el,event,d) {
16887 this.fireEvent('evententer', this, el, event);
16890 onEventLeave: function (e, el,event,d) {
16891 this.fireEvent('eventleave', this, el, event);
16894 onEventClick: function (e, el,event,d) {
16895 this.fireEvent('eventclick', this, el, event);
16898 onMonthChange: function () {
16902 onMoreEventClick: function(e, el, more)
16906 this.calpopover.placement = 'right';
16907 this.calpopover.setTitle('More');
16909 this.calpopover.setContent('');
16911 var ctr = this.calpopover.el.select('.popover-content', true).first();
16913 Roo.each(more, function(m){
16915 cls : 'fc-event-hori fc-event-draggable',
16918 var cg = ctr.createChild(cfg);
16920 cg.on('click', _this.onEventClick, _this, m);
16923 this.calpopover.show(el);
16928 onLoad: function ()
16930 this.calevents = [];
16933 if(this.store.getCount() > 0){
16934 this.store.data.each(function(d){
16937 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16938 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16939 time : d.data.start_time,
16940 title : d.data.title,
16941 description : d.data.description,
16942 venue : d.data.venue
16947 this.renderEvents();
16949 if(this.calevents.length && this.loadMask){
16950 this.maskEl.hide();
16954 onBeforeLoad: function()
16956 this.clearEvents();
16958 this.maskEl.show();
16972 * @class Roo.bootstrap.Popover
16973 * @extends Roo.bootstrap.Component
16974 * Bootstrap Popover class
16975 * @cfg {String} html contents of the popover (or false to use children..)
16976 * @cfg {String} title of popover (or false to hide)
16977 * @cfg {String} placement how it is placed
16978 * @cfg {String} trigger click || hover (or false to trigger manually)
16979 * @cfg {String} over what (parent or false to trigger manually.)
16980 * @cfg {Number} delay - delay before showing
16983 * Create a new Popover
16984 * @param {Object} config The config object
16987 Roo.bootstrap.Popover = function(config){
16988 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16994 * After the popover show
16996 * @param {Roo.bootstrap.Popover} this
17001 * After the popover hide
17003 * @param {Roo.bootstrap.Popover} this
17009 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17011 title: 'Fill in a title',
17014 placement : 'right',
17015 trigger : 'hover', // hover
17021 can_build_overlaid : false,
17023 getChildContainer : function()
17025 return this.el.select('.popover-content',true).first();
17028 getAutoCreate : function(){
17031 cls : 'popover roo-dynamic',
17032 style: 'display:block',
17038 cls : 'popover-inner',
17042 cls: 'popover-title',
17046 cls : 'popover-content',
17057 setTitle: function(str)
17060 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17062 setContent: function(str)
17065 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17067 // as it get's added to the bottom of the page.
17068 onRender : function(ct, position)
17070 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17072 var cfg = Roo.apply({}, this.getAutoCreate());
17076 cfg.cls += ' ' + this.cls;
17079 cfg.style = this.style;
17081 //Roo.log("adding to ");
17082 this.el = Roo.get(document.body).createChild(cfg, position);
17083 // Roo.log(this.el);
17088 initEvents : function()
17090 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17091 this.el.enableDisplayMode('block');
17093 if (this.over === false) {
17096 if (this.triggers === false) {
17099 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17100 var triggers = this.trigger ? this.trigger.split(' ') : [];
17101 Roo.each(triggers, function(trigger) {
17103 if (trigger == 'click') {
17104 on_el.on('click', this.toggle, this);
17105 } else if (trigger != 'manual') {
17106 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17107 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17109 on_el.on(eventIn ,this.enter, this);
17110 on_el.on(eventOut, this.leave, this);
17121 toggle : function () {
17122 this.hoverState == 'in' ? this.leave() : this.enter();
17125 enter : function () {
17127 clearTimeout(this.timeout);
17129 this.hoverState = 'in';
17131 if (!this.delay || !this.delay.show) {
17136 this.timeout = setTimeout(function () {
17137 if (_t.hoverState == 'in') {
17140 }, this.delay.show)
17143 leave : function() {
17144 clearTimeout(this.timeout);
17146 this.hoverState = 'out';
17148 if (!this.delay || !this.delay.hide) {
17153 this.timeout = setTimeout(function () {
17154 if (_t.hoverState == 'out') {
17157 }, this.delay.hide)
17160 show : function (on_el)
17163 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17167 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17168 if (this.html !== false) {
17169 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17171 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17172 if (!this.title.length) {
17173 this.el.select('.popover-title',true).hide();
17176 var placement = typeof this.placement == 'function' ?
17177 this.placement.call(this, this.el, on_el) :
17180 var autoToken = /\s?auto?\s?/i;
17181 var autoPlace = autoToken.test(placement);
17183 placement = placement.replace(autoToken, '') || 'top';
17187 //this.el.setXY([0,0]);
17189 this.el.dom.style.display='block';
17190 this.el.addClass(placement);
17192 //this.el.appendTo(on_el);
17194 var p = this.getPosition();
17195 var box = this.el.getBox();
17200 var align = Roo.bootstrap.Popover.alignment[placement];
17201 this.el.alignTo(on_el, align[0],align[1]);
17202 //var arrow = this.el.select('.arrow',true).first();
17203 //arrow.set(align[2],
17205 this.el.addClass('in');
17208 if (this.el.hasClass('fade')) {
17212 this.hoverState = 'in';
17214 this.fireEvent('show', this);
17219 this.el.setXY([0,0]);
17220 this.el.removeClass('in');
17222 this.hoverState = null;
17224 this.fireEvent('hide', this);
17229 Roo.bootstrap.Popover.alignment = {
17230 'left' : ['r-l', [-10,0], 'right'],
17231 'right' : ['l-r', [10,0], 'left'],
17232 'bottom' : ['t-b', [0,10], 'top'],
17233 'top' : [ 'b-t', [0,-10], 'bottom']
17244 * @class Roo.bootstrap.Progress
17245 * @extends Roo.bootstrap.Component
17246 * Bootstrap Progress class
17247 * @cfg {Boolean} striped striped of the progress bar
17248 * @cfg {Boolean} active animated of the progress bar
17252 * Create a new Progress
17253 * @param {Object} config The config object
17256 Roo.bootstrap.Progress = function(config){
17257 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17260 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17265 getAutoCreate : function(){
17273 cfg.cls += ' progress-striped';
17277 cfg.cls += ' active';
17296 * @class Roo.bootstrap.ProgressBar
17297 * @extends Roo.bootstrap.Component
17298 * Bootstrap ProgressBar class
17299 * @cfg {Number} aria_valuenow aria-value now
17300 * @cfg {Number} aria_valuemin aria-value min
17301 * @cfg {Number} aria_valuemax aria-value max
17302 * @cfg {String} label label for the progress bar
17303 * @cfg {String} panel (success | info | warning | danger )
17304 * @cfg {String} role role of the progress bar
17305 * @cfg {String} sr_only text
17309 * Create a new ProgressBar
17310 * @param {Object} config The config object
17313 Roo.bootstrap.ProgressBar = function(config){
17314 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17317 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17321 aria_valuemax : 100,
17327 getAutoCreate : function()
17332 cls: 'progress-bar',
17333 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17345 cfg.role = this.role;
17348 if(this.aria_valuenow){
17349 cfg['aria-valuenow'] = this.aria_valuenow;
17352 if(this.aria_valuemin){
17353 cfg['aria-valuemin'] = this.aria_valuemin;
17356 if(this.aria_valuemax){
17357 cfg['aria-valuemax'] = this.aria_valuemax;
17360 if(this.label && !this.sr_only){
17361 cfg.html = this.label;
17365 cfg.cls += ' progress-bar-' + this.panel;
17371 update : function(aria_valuenow)
17373 this.aria_valuenow = aria_valuenow;
17375 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17390 * @class Roo.bootstrap.TabGroup
17391 * @extends Roo.bootstrap.Column
17392 * Bootstrap Column class
17393 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17394 * @cfg {Boolean} carousel true to make the group behave like a carousel
17395 * @cfg {Boolean} bullets show bullets for the panels
17396 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17397 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17398 * @cfg {Boolean} showarrow (true|false) show arrow default true
17401 * Create a new TabGroup
17402 * @param {Object} config The config object
17405 Roo.bootstrap.TabGroup = function(config){
17406 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17408 this.navId = Roo.id();
17411 Roo.bootstrap.TabGroup.register(this);
17415 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17418 transition : false,
17423 slideOnTouch : false,
17426 getAutoCreate : function()
17428 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17430 cfg.cls += ' tab-content';
17432 if (this.carousel) {
17433 cfg.cls += ' carousel slide';
17436 cls : 'carousel-inner',
17440 if(this.bullets && !Roo.isTouch){
17443 cls : 'carousel-bullets',
17447 if(this.bullets_cls){
17448 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17455 cfg.cn[0].cn.push(bullets);
17458 if(this.showarrow){
17459 cfg.cn[0].cn.push({
17461 class : 'carousel-arrow',
17465 class : 'carousel-prev',
17469 class : 'fa fa-chevron-left'
17475 class : 'carousel-next',
17479 class : 'fa fa-chevron-right'
17492 initEvents: function()
17494 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17495 // this.el.on("touchstart", this.onTouchStart, this);
17498 if(this.autoslide){
17501 this.slideFn = window.setInterval(function() {
17502 _this.showPanelNext();
17506 if(this.showarrow){
17507 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17508 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17514 // onTouchStart : function(e, el, o)
17516 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17520 // this.showPanelNext();
17524 getChildContainer : function()
17526 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17530 * register a Navigation item
17531 * @param {Roo.bootstrap.NavItem} the navitem to add
17533 register : function(item)
17535 this.tabs.push( item);
17536 item.navId = this.navId; // not really needed..
17541 getActivePanel : function()
17544 Roo.each(this.tabs, function(t) {
17554 getPanelByName : function(n)
17557 Roo.each(this.tabs, function(t) {
17558 if (t.tabId == n) {
17566 indexOfPanel : function(p)
17569 Roo.each(this.tabs, function(t,i) {
17570 if (t.tabId == p.tabId) {
17579 * show a specific panel
17580 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17581 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17583 showPanel : function (pan)
17585 if(this.transition || typeof(pan) == 'undefined'){
17586 Roo.log("waiting for the transitionend");
17590 if (typeof(pan) == 'number') {
17591 pan = this.tabs[pan];
17594 if (typeof(pan) == 'string') {
17595 pan = this.getPanelByName(pan);
17598 var cur = this.getActivePanel();
17601 Roo.log('pan or acitve pan is undefined');
17605 if (pan.tabId == this.getActivePanel().tabId) {
17609 if (false === cur.fireEvent('beforedeactivate')) {
17613 if(this.bullets > 0 && !Roo.isTouch){
17614 this.setActiveBullet(this.indexOfPanel(pan));
17617 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17619 this.transition = true;
17620 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17621 var lr = dir == 'next' ? 'left' : 'right';
17622 pan.el.addClass(dir); // or prev
17623 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17624 cur.el.addClass(lr); // or right
17625 pan.el.addClass(lr);
17628 cur.el.on('transitionend', function() {
17629 Roo.log("trans end?");
17631 pan.el.removeClass([lr,dir]);
17632 pan.setActive(true);
17634 cur.el.removeClass([lr]);
17635 cur.setActive(false);
17637 _this.transition = false;
17639 }, this, { single: true } );
17644 cur.setActive(false);
17645 pan.setActive(true);
17650 showPanelNext : function()
17652 var i = this.indexOfPanel(this.getActivePanel());
17654 if (i >= this.tabs.length - 1 && !this.autoslide) {
17658 if (i >= this.tabs.length - 1 && this.autoslide) {
17662 this.showPanel(this.tabs[i+1]);
17665 showPanelPrev : function()
17667 var i = this.indexOfPanel(this.getActivePanel());
17669 if (i < 1 && !this.autoslide) {
17673 if (i < 1 && this.autoslide) {
17674 i = this.tabs.length;
17677 this.showPanel(this.tabs[i-1]);
17681 addBullet: function()
17683 if(!this.bullets || Roo.isTouch){
17686 var ctr = this.el.select('.carousel-bullets',true).first();
17687 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17688 var bullet = ctr.createChild({
17689 cls : 'bullet bullet-' + i
17690 },ctr.dom.lastChild);
17695 bullet.on('click', (function(e, el, o, ii, t){
17697 e.preventDefault();
17699 this.showPanel(ii);
17701 if(this.autoslide && this.slideFn){
17702 clearInterval(this.slideFn);
17703 this.slideFn = window.setInterval(function() {
17704 _this.showPanelNext();
17708 }).createDelegate(this, [i, bullet], true));
17713 setActiveBullet : function(i)
17719 Roo.each(this.el.select('.bullet', true).elements, function(el){
17720 el.removeClass('selected');
17723 var bullet = this.el.select('.bullet-' + i, true).first();
17729 bullet.addClass('selected');
17740 Roo.apply(Roo.bootstrap.TabGroup, {
17744 * register a Navigation Group
17745 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17747 register : function(navgrp)
17749 this.groups[navgrp.navId] = navgrp;
17753 * fetch a Navigation Group based on the navigation ID
17754 * if one does not exist , it will get created.
17755 * @param {string} the navgroup to add
17756 * @returns {Roo.bootstrap.NavGroup} the navgroup
17758 get: function(navId) {
17759 if (typeof(this.groups[navId]) == 'undefined') {
17760 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17762 return this.groups[navId] ;
17777 * @class Roo.bootstrap.TabPanel
17778 * @extends Roo.bootstrap.Component
17779 * Bootstrap TabPanel class
17780 * @cfg {Boolean} active panel active
17781 * @cfg {String} html panel content
17782 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17783 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17784 * @cfg {String} href click to link..
17788 * Create a new TabPanel
17789 * @param {Object} config The config object
17792 Roo.bootstrap.TabPanel = function(config){
17793 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17797 * Fires when the active status changes
17798 * @param {Roo.bootstrap.TabPanel} this
17799 * @param {Boolean} state the new state
17804 * @event beforedeactivate
17805 * Fires before a tab is de-activated - can be used to do validation on a form.
17806 * @param {Roo.bootstrap.TabPanel} this
17807 * @return {Boolean} false if there is an error
17810 'beforedeactivate': true
17813 this.tabId = this.tabId || Roo.id();
17817 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17825 getAutoCreate : function(){
17828 // item is needed for carousel - not sure if it has any effect otherwise
17829 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17830 html: this.html || ''
17834 cfg.cls += ' active';
17838 cfg.tabId = this.tabId;
17845 initEvents: function()
17847 var p = this.parent();
17849 this.navId = this.navId || p.navId;
17851 if (typeof(this.navId) != 'undefined') {
17852 // not really needed.. but just in case.. parent should be a NavGroup.
17853 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17857 var i = tg.tabs.length - 1;
17859 if(this.active && tg.bullets > 0 && i < tg.bullets){
17860 tg.setActiveBullet(i);
17864 this.el.on('click', this.onClick, this);
17867 this.el.on("touchstart", this.onTouchStart, this);
17868 this.el.on("touchmove", this.onTouchMove, this);
17869 this.el.on("touchend", this.onTouchEnd, this);
17874 onRender : function(ct, position)
17876 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17879 setActive : function(state)
17881 Roo.log("panel - set active " + this.tabId + "=" + state);
17883 this.active = state;
17885 this.el.removeClass('active');
17887 } else if (!this.el.hasClass('active')) {
17888 this.el.addClass('active');
17891 this.fireEvent('changed', this, state);
17894 onClick : function(e)
17896 e.preventDefault();
17898 if(!this.href.length){
17902 window.location.href = this.href;
17911 onTouchStart : function(e)
17913 this.swiping = false;
17915 this.startX = e.browserEvent.touches[0].clientX;
17916 this.startY = e.browserEvent.touches[0].clientY;
17919 onTouchMove : function(e)
17921 this.swiping = true;
17923 this.endX = e.browserEvent.touches[0].clientX;
17924 this.endY = e.browserEvent.touches[0].clientY;
17927 onTouchEnd : function(e)
17934 var tabGroup = this.parent();
17936 if(this.endX > this.startX){ // swiping right
17937 tabGroup.showPanelPrev();
17941 if(this.startX > this.endX){ // swiping left
17942 tabGroup.showPanelNext();
17961 * @class Roo.bootstrap.DateField
17962 * @extends Roo.bootstrap.Input
17963 * Bootstrap DateField class
17964 * @cfg {Number} weekStart default 0
17965 * @cfg {String} viewMode default empty, (months|years)
17966 * @cfg {String} minViewMode default empty, (months|years)
17967 * @cfg {Number} startDate default -Infinity
17968 * @cfg {Number} endDate default Infinity
17969 * @cfg {Boolean} todayHighlight default false
17970 * @cfg {Boolean} todayBtn default false
17971 * @cfg {Boolean} calendarWeeks default false
17972 * @cfg {Object} daysOfWeekDisabled default empty
17973 * @cfg {Boolean} singleMode default false (true | false)
17975 * @cfg {Boolean} keyboardNavigation default true
17976 * @cfg {String} language default en
17979 * Create a new DateField
17980 * @param {Object} config The config object
17983 Roo.bootstrap.DateField = function(config){
17984 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17988 * Fires when this field show.
17989 * @param {Roo.bootstrap.DateField} this
17990 * @param {Mixed} date The date value
17995 * Fires when this field hide.
17996 * @param {Roo.bootstrap.DateField} this
17997 * @param {Mixed} date The date value
18002 * Fires when select a date.
18003 * @param {Roo.bootstrap.DateField} this
18004 * @param {Mixed} date The date value
18008 * @event beforeselect
18009 * Fires when before select a date.
18010 * @param {Roo.bootstrap.DateField} this
18011 * @param {Mixed} date The date value
18013 beforeselect : true
18017 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18020 * @cfg {String} format
18021 * The default date format string which can be overriden for localization support. The format must be
18022 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18026 * @cfg {String} altFormats
18027 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18028 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18030 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18038 todayHighlight : false,
18044 keyboardNavigation: true,
18046 calendarWeeks: false,
18048 startDate: -Infinity,
18052 daysOfWeekDisabled: [],
18056 singleMode : false,
18058 UTCDate: function()
18060 return new Date(Date.UTC.apply(Date, arguments));
18063 UTCToday: function()
18065 var today = new Date();
18066 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18069 getDate: function() {
18070 var d = this.getUTCDate();
18071 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18074 getUTCDate: function() {
18078 setDate: function(d) {
18079 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18082 setUTCDate: function(d) {
18084 this.setValue(this.formatDate(this.date));
18087 onRender: function(ct, position)
18090 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18092 this.language = this.language || 'en';
18093 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18094 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18096 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18097 this.format = this.format || 'm/d/y';
18098 this.isInline = false;
18099 this.isInput = true;
18100 this.component = this.el.select('.add-on', true).first() || false;
18101 this.component = (this.component && this.component.length === 0) ? false : this.component;
18102 this.hasInput = this.component && this.inputEl().length;
18104 if (typeof(this.minViewMode === 'string')) {
18105 switch (this.minViewMode) {
18107 this.minViewMode = 1;
18110 this.minViewMode = 2;
18113 this.minViewMode = 0;
18118 if (typeof(this.viewMode === 'string')) {
18119 switch (this.viewMode) {
18132 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18134 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18136 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18138 this.picker().on('mousedown', this.onMousedown, this);
18139 this.picker().on('click', this.onClick, this);
18141 this.picker().addClass('datepicker-dropdown');
18143 this.startViewMode = this.viewMode;
18145 if(this.singleMode){
18146 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18147 v.setVisibilityMode(Roo.Element.DISPLAY);
18151 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18152 v.setStyle('width', '189px');
18156 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18157 if(!this.calendarWeeks){
18162 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18163 v.attr('colspan', function(i, val){
18164 return parseInt(val) + 1;
18169 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18171 this.setStartDate(this.startDate);
18172 this.setEndDate(this.endDate);
18174 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18181 if(this.isInline) {
18186 picker : function()
18188 return this.pickerEl;
18189 // return this.el.select('.datepicker', true).first();
18192 fillDow: function()
18194 var dowCnt = this.weekStart;
18203 if(this.calendarWeeks){
18211 while (dowCnt < this.weekStart + 7) {
18215 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18219 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18222 fillMonths: function()
18225 var months = this.picker().select('>.datepicker-months td', true).first();
18227 months.dom.innerHTML = '';
18233 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18236 months.createChild(month);
18243 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;
18245 if (this.date < this.startDate) {
18246 this.viewDate = new Date(this.startDate);
18247 } else if (this.date > this.endDate) {
18248 this.viewDate = new Date(this.endDate);
18250 this.viewDate = new Date(this.date);
18258 var d = new Date(this.viewDate),
18259 year = d.getUTCFullYear(),
18260 month = d.getUTCMonth(),
18261 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18262 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18263 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18264 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18265 currentDate = this.date && this.date.valueOf(),
18266 today = this.UTCToday();
18268 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18270 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18272 // this.picker.select('>tfoot th.today').
18273 // .text(dates[this.language].today)
18274 // .toggle(this.todayBtn !== false);
18276 this.updateNavArrows();
18279 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18281 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18283 prevMonth.setUTCDate(day);
18285 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18287 var nextMonth = new Date(prevMonth);
18289 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18291 nextMonth = nextMonth.valueOf();
18293 var fillMonths = false;
18295 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18297 while(prevMonth.valueOf() < nextMonth) {
18300 if (prevMonth.getUTCDay() === this.weekStart) {
18302 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18310 if(this.calendarWeeks){
18311 // ISO 8601: First week contains first thursday.
18312 // ISO also states week starts on Monday, but we can be more abstract here.
18314 // Start of current week: based on weekstart/current date
18315 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18316 // Thursday of this week
18317 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18318 // First Thursday of year, year from thursday
18319 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18320 // Calendar week: ms between thursdays, div ms per day, div 7 days
18321 calWeek = (th - yth) / 864e5 / 7 + 1;
18323 fillMonths.cn.push({
18331 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18333 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18336 if (this.todayHighlight &&
18337 prevMonth.getUTCFullYear() == today.getFullYear() &&
18338 prevMonth.getUTCMonth() == today.getMonth() &&
18339 prevMonth.getUTCDate() == today.getDate()) {
18340 clsName += ' today';
18343 if (currentDate && prevMonth.valueOf() === currentDate) {
18344 clsName += ' active';
18347 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18348 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18349 clsName += ' disabled';
18352 fillMonths.cn.push({
18354 cls: 'day ' + clsName,
18355 html: prevMonth.getDate()
18358 prevMonth.setDate(prevMonth.getDate()+1);
18361 var currentYear = this.date && this.date.getUTCFullYear();
18362 var currentMonth = this.date && this.date.getUTCMonth();
18364 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18366 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18367 v.removeClass('active');
18369 if(currentYear === year && k === currentMonth){
18370 v.addClass('active');
18373 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18374 v.addClass('disabled');
18380 year = parseInt(year/10, 10) * 10;
18382 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18384 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18387 for (var i = -1; i < 11; i++) {
18388 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18390 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18398 showMode: function(dir)
18401 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18404 Roo.each(this.picker().select('>div',true).elements, function(v){
18405 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18408 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18413 if(this.isInline) {
18417 this.picker().removeClass(['bottom', 'top']);
18419 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18421 * place to the top of element!
18425 this.picker().addClass('top');
18426 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18431 this.picker().addClass('bottom');
18433 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18436 parseDate : function(value)
18438 if(!value || value instanceof Date){
18441 var v = Date.parseDate(value, this.format);
18442 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18443 v = Date.parseDate(value, 'Y-m-d');
18445 if(!v && this.altFormats){
18446 if(!this.altFormatsArray){
18447 this.altFormatsArray = this.altFormats.split("|");
18449 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18450 v = Date.parseDate(value, this.altFormatsArray[i]);
18456 formatDate : function(date, fmt)
18458 return (!date || !(date instanceof Date)) ?
18459 date : date.dateFormat(fmt || this.format);
18462 onFocus : function()
18464 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18468 onBlur : function()
18470 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18472 var d = this.inputEl().getValue();
18481 this.picker().show();
18485 this.fireEvent('show', this, this.date);
18490 if(this.isInline) {
18493 this.picker().hide();
18494 this.viewMode = this.startViewMode;
18497 this.fireEvent('hide', this, this.date);
18501 onMousedown: function(e)
18503 e.stopPropagation();
18504 e.preventDefault();
18509 Roo.bootstrap.DateField.superclass.keyup.call(this);
18513 setValue: function(v)
18515 if(this.fireEvent('beforeselect', this, v) !== false){
18516 var d = new Date(this.parseDate(v) ).clearTime();
18518 if(isNaN(d.getTime())){
18519 this.date = this.viewDate = '';
18520 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18524 v = this.formatDate(d);
18526 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18528 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18532 this.fireEvent('select', this, this.date);
18536 getValue: function()
18538 return this.formatDate(this.date);
18541 fireKey: function(e)
18543 if (!this.picker().isVisible()){
18544 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18550 var dateChanged = false,
18552 newDate, newViewDate;
18557 e.preventDefault();
18561 if (!this.keyboardNavigation) {
18564 dir = e.keyCode == 37 ? -1 : 1;
18567 newDate = this.moveYear(this.date, dir);
18568 newViewDate = this.moveYear(this.viewDate, dir);
18569 } else if (e.shiftKey){
18570 newDate = this.moveMonth(this.date, dir);
18571 newViewDate = this.moveMonth(this.viewDate, dir);
18573 newDate = new Date(this.date);
18574 newDate.setUTCDate(this.date.getUTCDate() + dir);
18575 newViewDate = new Date(this.viewDate);
18576 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18578 if (this.dateWithinRange(newDate)){
18579 this.date = newDate;
18580 this.viewDate = newViewDate;
18581 this.setValue(this.formatDate(this.date));
18583 e.preventDefault();
18584 dateChanged = true;
18589 if (!this.keyboardNavigation) {
18592 dir = e.keyCode == 38 ? -1 : 1;
18594 newDate = this.moveYear(this.date, dir);
18595 newViewDate = this.moveYear(this.viewDate, dir);
18596 } else if (e.shiftKey){
18597 newDate = this.moveMonth(this.date, dir);
18598 newViewDate = this.moveMonth(this.viewDate, dir);
18600 newDate = new Date(this.date);
18601 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18602 newViewDate = new Date(this.viewDate);
18603 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18605 if (this.dateWithinRange(newDate)){
18606 this.date = newDate;
18607 this.viewDate = newViewDate;
18608 this.setValue(this.formatDate(this.date));
18610 e.preventDefault();
18611 dateChanged = true;
18615 this.setValue(this.formatDate(this.date));
18617 e.preventDefault();
18620 this.setValue(this.formatDate(this.date));
18634 onClick: function(e)
18636 e.stopPropagation();
18637 e.preventDefault();
18639 var target = e.getTarget();
18641 if(target.nodeName.toLowerCase() === 'i'){
18642 target = Roo.get(target).dom.parentNode;
18645 var nodeName = target.nodeName;
18646 var className = target.className;
18647 var html = target.innerHTML;
18648 //Roo.log(nodeName);
18650 switch(nodeName.toLowerCase()) {
18652 switch(className) {
18658 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18659 switch(this.viewMode){
18661 this.viewDate = this.moveMonth(this.viewDate, dir);
18665 this.viewDate = this.moveYear(this.viewDate, dir);
18671 var date = new Date();
18672 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18674 this.setValue(this.formatDate(this.date));
18681 if (className.indexOf('disabled') < 0) {
18682 this.viewDate.setUTCDate(1);
18683 if (className.indexOf('month') > -1) {
18684 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18686 var year = parseInt(html, 10) || 0;
18687 this.viewDate.setUTCFullYear(year);
18691 if(this.singleMode){
18692 this.setValue(this.formatDate(this.viewDate));
18703 //Roo.log(className);
18704 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18705 var day = parseInt(html, 10) || 1;
18706 var year = this.viewDate.getUTCFullYear(),
18707 month = this.viewDate.getUTCMonth();
18709 if (className.indexOf('old') > -1) {
18716 } else if (className.indexOf('new') > -1) {
18724 //Roo.log([year,month,day]);
18725 this.date = this.UTCDate(year, month, day,0,0,0,0);
18726 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18728 //Roo.log(this.formatDate(this.date));
18729 this.setValue(this.formatDate(this.date));
18736 setStartDate: function(startDate)
18738 this.startDate = startDate || -Infinity;
18739 if (this.startDate !== -Infinity) {
18740 this.startDate = this.parseDate(this.startDate);
18743 this.updateNavArrows();
18746 setEndDate: function(endDate)
18748 this.endDate = endDate || Infinity;
18749 if (this.endDate !== Infinity) {
18750 this.endDate = this.parseDate(this.endDate);
18753 this.updateNavArrows();
18756 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18758 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18759 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18760 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18762 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18763 return parseInt(d, 10);
18766 this.updateNavArrows();
18769 updateNavArrows: function()
18771 if(this.singleMode){
18775 var d = new Date(this.viewDate),
18776 year = d.getUTCFullYear(),
18777 month = d.getUTCMonth();
18779 Roo.each(this.picker().select('.prev', true).elements, function(v){
18781 switch (this.viewMode) {
18784 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18790 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18797 Roo.each(this.picker().select('.next', true).elements, function(v){
18799 switch (this.viewMode) {
18802 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18808 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18816 moveMonth: function(date, dir)
18821 var new_date = new Date(date.valueOf()),
18822 day = new_date.getUTCDate(),
18823 month = new_date.getUTCMonth(),
18824 mag = Math.abs(dir),
18826 dir = dir > 0 ? 1 : -1;
18829 // If going back one month, make sure month is not current month
18830 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18832 return new_date.getUTCMonth() == month;
18834 // If going forward one month, make sure month is as expected
18835 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18837 return new_date.getUTCMonth() != new_month;
18839 new_month = month + dir;
18840 new_date.setUTCMonth(new_month);
18841 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18842 if (new_month < 0 || new_month > 11) {
18843 new_month = (new_month + 12) % 12;
18846 // For magnitudes >1, move one month at a time...
18847 for (var i=0; i<mag; i++) {
18848 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18849 new_date = this.moveMonth(new_date, dir);
18851 // ...then reset the day, keeping it in the new month
18852 new_month = new_date.getUTCMonth();
18853 new_date.setUTCDate(day);
18855 return new_month != new_date.getUTCMonth();
18858 // Common date-resetting loop -- if date is beyond end of month, make it
18861 new_date.setUTCDate(--day);
18862 new_date.setUTCMonth(new_month);
18867 moveYear: function(date, dir)
18869 return this.moveMonth(date, dir*12);
18872 dateWithinRange: function(date)
18874 return date >= this.startDate && date <= this.endDate;
18880 this.picker().remove();
18883 validateValue : function(value)
18885 if(value.length < 1) {
18886 if(this.allowBlank){
18892 if(value.length < this.minLength){
18895 if(value.length > this.maxLength){
18899 var vt = Roo.form.VTypes;
18900 if(!vt[this.vtype](value, this)){
18904 if(typeof this.validator == "function"){
18905 var msg = this.validator(value);
18911 if(this.regex && !this.regex.test(value)){
18915 if(typeof(this.parseDate(value)) == 'undefined'){
18919 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18923 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18933 Roo.apply(Roo.bootstrap.DateField, {
18944 html: '<i class="fa fa-arrow-left"/>'
18954 html: '<i class="fa fa-arrow-right"/>'
18996 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18997 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18998 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18999 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19000 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19013 navFnc: 'FullYear',
19018 navFnc: 'FullYear',
19023 Roo.apply(Roo.bootstrap.DateField, {
19027 cls: 'datepicker dropdown-menu roo-dynamic',
19031 cls: 'datepicker-days',
19035 cls: 'table-condensed',
19037 Roo.bootstrap.DateField.head,
19041 Roo.bootstrap.DateField.footer
19048 cls: 'datepicker-months',
19052 cls: 'table-condensed',
19054 Roo.bootstrap.DateField.head,
19055 Roo.bootstrap.DateField.content,
19056 Roo.bootstrap.DateField.footer
19063 cls: 'datepicker-years',
19067 cls: 'table-condensed',
19069 Roo.bootstrap.DateField.head,
19070 Roo.bootstrap.DateField.content,
19071 Roo.bootstrap.DateField.footer
19090 * @class Roo.bootstrap.TimeField
19091 * @extends Roo.bootstrap.Input
19092 * Bootstrap DateField class
19096 * Create a new TimeField
19097 * @param {Object} config The config object
19100 Roo.bootstrap.TimeField = function(config){
19101 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19105 * Fires when this field show.
19106 * @param {Roo.bootstrap.DateField} thisthis
19107 * @param {Mixed} date The date value
19112 * Fires when this field hide.
19113 * @param {Roo.bootstrap.DateField} this
19114 * @param {Mixed} date The date value
19119 * Fires when select a date.
19120 * @param {Roo.bootstrap.DateField} this
19121 * @param {Mixed} date The date value
19127 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19130 * @cfg {String} format
19131 * The default time format string which can be overriden for localization support. The format must be
19132 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19136 onRender: function(ct, position)
19139 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19141 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19143 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19145 this.pop = this.picker().select('>.datepicker-time',true).first();
19146 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19148 this.picker().on('mousedown', this.onMousedown, this);
19149 this.picker().on('click', this.onClick, this);
19151 this.picker().addClass('datepicker-dropdown');
19156 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19157 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19158 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19159 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19160 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19161 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19165 fireKey: function(e){
19166 if (!this.picker().isVisible()){
19167 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19173 e.preventDefault();
19181 this.onTogglePeriod();
19184 this.onIncrementMinutes();
19187 this.onDecrementMinutes();
19196 onClick: function(e) {
19197 e.stopPropagation();
19198 e.preventDefault();
19201 picker : function()
19203 return this.el.select('.datepicker', true).first();
19206 fillTime: function()
19208 var time = this.pop.select('tbody', true).first();
19210 time.dom.innerHTML = '';
19225 cls: 'hours-up glyphicon glyphicon-chevron-up'
19245 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19266 cls: 'timepicker-hour',
19281 cls: 'timepicker-minute',
19296 cls: 'btn btn-primary period',
19318 cls: 'hours-down glyphicon glyphicon-chevron-down'
19338 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19356 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19363 var hours = this.time.getHours();
19364 var minutes = this.time.getMinutes();
19377 hours = hours - 12;
19381 hours = '0' + hours;
19385 minutes = '0' + minutes;
19388 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19389 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19390 this.pop.select('button', true).first().dom.innerHTML = period;
19396 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19398 var cls = ['bottom'];
19400 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19407 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19412 this.picker().addClass(cls.join('-'));
19416 Roo.each(cls, function(c){
19418 _this.picker().setTop(_this.inputEl().getHeight());
19422 _this.picker().setTop(0 - _this.picker().getHeight());
19427 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19431 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19438 onFocus : function()
19440 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19444 onBlur : function()
19446 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19452 this.picker().show();
19457 this.fireEvent('show', this, this.date);
19462 this.picker().hide();
19465 this.fireEvent('hide', this, this.date);
19468 setTime : function()
19471 this.setValue(this.time.format(this.format));
19473 this.fireEvent('select', this, this.date);
19478 onMousedown: function(e){
19479 e.stopPropagation();
19480 e.preventDefault();
19483 onIncrementHours: function()
19485 Roo.log('onIncrementHours');
19486 this.time = this.time.add(Date.HOUR, 1);
19491 onDecrementHours: function()
19493 Roo.log('onDecrementHours');
19494 this.time = this.time.add(Date.HOUR, -1);
19498 onIncrementMinutes: function()
19500 Roo.log('onIncrementMinutes');
19501 this.time = this.time.add(Date.MINUTE, 1);
19505 onDecrementMinutes: function()
19507 Roo.log('onDecrementMinutes');
19508 this.time = this.time.add(Date.MINUTE, -1);
19512 onTogglePeriod: function()
19514 Roo.log('onTogglePeriod');
19515 this.time = this.time.add(Date.HOUR, 12);
19522 Roo.apply(Roo.bootstrap.TimeField, {
19552 cls: 'btn btn-info ok',
19564 Roo.apply(Roo.bootstrap.TimeField, {
19568 cls: 'datepicker dropdown-menu',
19572 cls: 'datepicker-time',
19576 cls: 'table-condensed',
19578 Roo.bootstrap.TimeField.content,
19579 Roo.bootstrap.TimeField.footer
19598 * @class Roo.bootstrap.MonthField
19599 * @extends Roo.bootstrap.Input
19600 * Bootstrap MonthField class
19602 * @cfg {String} language default en
19605 * Create a new MonthField
19606 * @param {Object} config The config object
19609 Roo.bootstrap.MonthField = function(config){
19610 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19615 * Fires when this field show.
19616 * @param {Roo.bootstrap.MonthField} this
19617 * @param {Mixed} date The date value
19622 * Fires when this field hide.
19623 * @param {Roo.bootstrap.MonthField} this
19624 * @param {Mixed} date The date value
19629 * Fires when select a date.
19630 * @param {Roo.bootstrap.MonthField} this
19631 * @param {String} oldvalue The old value
19632 * @param {String} newvalue The new value
19638 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19640 onRender: function(ct, position)
19643 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19645 this.language = this.language || 'en';
19646 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19647 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19649 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19650 this.isInline = false;
19651 this.isInput = true;
19652 this.component = this.el.select('.add-on', true).first() || false;
19653 this.component = (this.component && this.component.length === 0) ? false : this.component;
19654 this.hasInput = this.component && this.inputEL().length;
19656 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19658 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19660 this.picker().on('mousedown', this.onMousedown, this);
19661 this.picker().on('click', this.onClick, this);
19663 this.picker().addClass('datepicker-dropdown');
19665 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19666 v.setStyle('width', '189px');
19673 if(this.isInline) {
19679 setValue: function(v, suppressEvent)
19681 var o = this.getValue();
19683 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19687 if(suppressEvent !== true){
19688 this.fireEvent('select', this, o, v);
19693 getValue: function()
19698 onClick: function(e)
19700 e.stopPropagation();
19701 e.preventDefault();
19703 var target = e.getTarget();
19705 if(target.nodeName.toLowerCase() === 'i'){
19706 target = Roo.get(target).dom.parentNode;
19709 var nodeName = target.nodeName;
19710 var className = target.className;
19711 var html = target.innerHTML;
19713 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19717 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19719 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19725 picker : function()
19727 return this.pickerEl;
19730 fillMonths: function()
19733 var months = this.picker().select('>.datepicker-months td', true).first();
19735 months.dom.innerHTML = '';
19741 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19744 months.createChild(month);
19753 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19754 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19757 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19758 e.removeClass('active');
19760 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19761 e.addClass('active');
19768 if(this.isInline) {
19772 this.picker().removeClass(['bottom', 'top']);
19774 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19776 * place to the top of element!
19780 this.picker().addClass('top');
19781 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19786 this.picker().addClass('bottom');
19788 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19791 onFocus : function()
19793 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19797 onBlur : function()
19799 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19801 var d = this.inputEl().getValue();
19810 this.picker().show();
19811 this.picker().select('>.datepicker-months', true).first().show();
19815 this.fireEvent('show', this, this.date);
19820 if(this.isInline) {
19823 this.picker().hide();
19824 this.fireEvent('hide', this, this.date);
19828 onMousedown: function(e)
19830 e.stopPropagation();
19831 e.preventDefault();
19836 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19840 fireKey: function(e)
19842 if (!this.picker().isVisible()){
19843 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19854 e.preventDefault();
19858 dir = e.keyCode == 37 ? -1 : 1;
19860 this.vIndex = this.vIndex + dir;
19862 if(this.vIndex < 0){
19866 if(this.vIndex > 11){
19870 if(isNaN(this.vIndex)){
19874 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19880 dir = e.keyCode == 38 ? -1 : 1;
19882 this.vIndex = this.vIndex + dir * 4;
19884 if(this.vIndex < 0){
19888 if(this.vIndex > 11){
19892 if(isNaN(this.vIndex)){
19896 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19901 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19902 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19906 e.preventDefault();
19909 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19910 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19926 this.picker().remove();
19931 Roo.apply(Roo.bootstrap.MonthField, {
19950 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19951 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19956 Roo.apply(Roo.bootstrap.MonthField, {
19960 cls: 'datepicker dropdown-menu roo-dynamic',
19964 cls: 'datepicker-months',
19968 cls: 'table-condensed',
19970 Roo.bootstrap.DateField.content
19990 * @class Roo.bootstrap.CheckBox
19991 * @extends Roo.bootstrap.Input
19992 * Bootstrap CheckBox class
19994 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19995 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19996 * @cfg {String} boxLabel The text that appears beside the checkbox
19997 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19998 * @cfg {Boolean} checked initnal the element
19999 * @cfg {Boolean} inline inline the element (default false)
20000 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20003 * Create a new CheckBox
20004 * @param {Object} config The config object
20007 Roo.bootstrap.CheckBox = function(config){
20008 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20013 * Fires when the element is checked or unchecked.
20014 * @param {Roo.bootstrap.CheckBox} this This input
20015 * @param {Boolean} checked The new checked value
20022 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20024 inputType: 'checkbox',
20032 getAutoCreate : function()
20034 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20040 cfg.cls = 'form-group ' + this.inputType; //input-group
20043 cfg.cls += ' ' + this.inputType + '-inline';
20049 type : this.inputType,
20050 value : this.inputValue,
20051 cls : 'roo-' + this.inputType, //'form-box',
20052 placeholder : this.placeholder || ''
20056 if(this.inputType != 'radio'){
20060 cls : 'roo-hidden-value',
20061 value : this.checked ? this.valueOff : this.inputValue
20066 if (this.weight) { // Validity check?
20067 cfg.cls += " " + this.inputType + "-" + this.weight;
20070 if (this.disabled) {
20071 input.disabled=true;
20075 input.checked = this.checked;
20082 input.name = this.name;
20084 if(this.inputType != 'radio'){
20085 hidden.name = this.name;
20086 input.name = '_hidden_' + this.name;
20091 input.cls += ' input-' + this.size;
20096 ['xs','sm','md','lg'].map(function(size){
20097 if (settings[size]) {
20098 cfg.cls += ' col-' + size + '-' + settings[size];
20102 var inputblock = input;
20104 if (this.before || this.after) {
20107 cls : 'input-group',
20112 inputblock.cn.push({
20114 cls : 'input-group-addon',
20119 inputblock.cn.push(input);
20121 if(this.inputType != 'radio'){
20122 inputblock.cn.push(hidden);
20126 inputblock.cn.push({
20128 cls : 'input-group-addon',
20135 if (align ==='left' && this.fieldLabel.length) {
20136 // Roo.log("left and has label");
20141 cls : 'control-label',
20142 html : this.fieldLabel
20153 if(this.labelWidth > 12){
20154 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20157 if(this.labelWidth < 13 && this.labelmd == 0){
20158 this.labelmd = this.labelWidth;
20161 if(this.labellg > 0){
20162 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20163 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20166 if(this.labelmd > 0){
20167 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20168 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20171 if(this.labelsm > 0){
20172 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20173 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20176 if(this.labelxs > 0){
20177 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20178 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20181 } else if ( this.fieldLabel.length) {
20182 // Roo.log(" label");
20186 tag: this.boxLabel ? 'span' : 'label',
20188 cls: 'control-label box-input-label',
20189 //cls : 'input-group-addon',
20190 html : this.fieldLabel
20200 // Roo.log(" no label && no align");
20201 cfg.cn = [ inputblock ] ;
20207 var boxLabelCfg = {
20209 //'for': id, // box label is handled by onclick - so no for...
20211 html: this.boxLabel
20215 boxLabelCfg.tooltip = this.tooltip;
20218 cfg.cn.push(boxLabelCfg);
20221 if(this.inputType != 'radio'){
20222 cfg.cn.push(hidden);
20230 * return the real input element.
20232 inputEl: function ()
20234 return this.el.select('input.roo-' + this.inputType,true).first();
20236 hiddenEl: function ()
20238 return this.el.select('input.roo-hidden-value',true).first();
20241 labelEl: function()
20243 return this.el.select('label.control-label',true).first();
20245 /* depricated... */
20249 return this.labelEl();
20252 boxLabelEl: function()
20254 return this.el.select('label.box-label',true).first();
20257 initEvents : function()
20259 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20261 this.inputEl().on('click', this.onClick, this);
20263 if (this.boxLabel) {
20264 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20267 this.startValue = this.getValue();
20270 Roo.bootstrap.CheckBox.register(this);
20274 onClick : function()
20276 this.setChecked(!this.checked);
20279 setChecked : function(state,suppressEvent)
20281 this.startValue = this.getValue();
20283 if(this.inputType == 'radio'){
20285 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20286 e.dom.checked = false;
20289 this.inputEl().dom.checked = true;
20291 this.inputEl().dom.value = this.inputValue;
20293 if(suppressEvent !== true){
20294 this.fireEvent('check', this, true);
20302 this.checked = state;
20304 this.inputEl().dom.checked = state;
20307 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20309 if(suppressEvent !== true){
20310 this.fireEvent('check', this, state);
20316 getValue : function()
20318 if(this.inputType == 'radio'){
20319 return this.getGroupValue();
20322 return this.hiddenEl().dom.value;
20326 getGroupValue : function()
20328 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20332 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20335 setValue : function(v,suppressEvent)
20337 if(this.inputType == 'radio'){
20338 this.setGroupValue(v, suppressEvent);
20342 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20347 setGroupValue : function(v, suppressEvent)
20349 this.startValue = this.getValue();
20351 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20352 e.dom.checked = false;
20354 if(e.dom.value == v){
20355 e.dom.checked = true;
20359 if(suppressEvent !== true){
20360 this.fireEvent('check', this, true);
20368 validate : function()
20372 (this.inputType == 'radio' && this.validateRadio()) ||
20373 (this.inputType == 'checkbox' && this.validateCheckbox())
20379 this.markInvalid();
20383 validateRadio : function()
20385 if(this.allowBlank){
20391 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20392 if(!e.dom.checked){
20404 validateCheckbox : function()
20407 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20408 //return (this.getValue() == this.inputValue) ? true : false;
20411 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20419 for(var i in group){
20424 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20431 * Mark this field as valid
20433 markValid : function()
20437 this.fireEvent('valid', this);
20439 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20442 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20449 if(this.inputType == 'radio'){
20450 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20451 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20452 e.findParent('.form-group', false, true).addClass(_this.validClass);
20459 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20460 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20464 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20470 for(var i in group){
20471 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20472 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20477 * Mark this field as invalid
20478 * @param {String} msg The validation message
20480 markInvalid : function(msg)
20482 if(this.allowBlank){
20488 this.fireEvent('invalid', this, msg);
20490 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20493 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20497 label.markInvalid();
20500 if(this.inputType == 'radio'){
20501 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20502 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20503 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20510 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20511 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20515 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20521 for(var i in group){
20522 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20523 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20528 clearInvalid : function()
20530 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20532 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20534 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20537 label.iconEl.removeClass(label.validClass);
20538 label.iconEl.removeClass(label.invalidClass);
20542 disable : function()
20544 if(this.inputType != 'radio'){
20545 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20552 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20553 _this.getActionEl().addClass(this.disabledClass);
20554 e.dom.disabled = true;
20558 this.disabled = true;
20559 this.fireEvent("disable", this);
20563 enable : function()
20565 if(this.inputType != 'radio'){
20566 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20573 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20574 _this.getActionEl().removeClass(this.disabledClass);
20575 e.dom.disabled = false;
20579 this.disabled = false;
20580 this.fireEvent("enable", this);
20586 Roo.apply(Roo.bootstrap.CheckBox, {
20591 * register a CheckBox Group
20592 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20594 register : function(checkbox)
20596 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20597 this.groups[checkbox.groupId] = {};
20600 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20604 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20608 * fetch a CheckBox Group based on the group ID
20609 * @param {string} the group ID
20610 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20612 get: function(groupId) {
20613 if (typeof(this.groups[groupId]) == 'undefined') {
20617 return this.groups[groupId] ;
20630 * @class Roo.bootstrap.Radio
20631 * @extends Roo.bootstrap.Component
20632 * Bootstrap Radio class
20633 * @cfg {String} boxLabel - the label associated
20634 * @cfg {String} value - the value of radio
20637 * Create a new Radio
20638 * @param {Object} config The config object
20640 Roo.bootstrap.Radio = function(config){
20641 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20645 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20651 getAutoCreate : function()
20655 cls : 'form-group radio',
20660 html : this.boxLabel
20668 initEvents : function()
20670 this.parent().register(this);
20672 this.el.on('click', this.onClick, this);
20676 onClick : function()
20678 this.setChecked(true);
20681 setChecked : function(state, suppressEvent)
20683 this.parent().setValue(this.value, suppressEvent);
20698 * @class Roo.bootstrap.SecurePass
20699 * @extends Roo.bootstrap.Input
20700 * Bootstrap SecurePass class
20704 * Create a new SecurePass
20705 * @param {Object} config The config object
20708 Roo.bootstrap.SecurePass = function (config) {
20709 // these go here, so the translation tool can replace them..
20711 PwdEmpty: "Please type a password, and then retype it to confirm.",
20712 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20713 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20714 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20715 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20716 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20717 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20718 TooWeak: "Your password is Too Weak."
20720 this.meterLabel = "Password strength:";
20721 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20722 this.meterClass = ["roo-password-meter-tooweak",
20723 "roo-password-meter-weak",
20724 "roo-password-meter-medium",
20725 "roo-password-meter-strong",
20726 "roo-password-meter-grey"],
20727 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20730 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20732 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20734 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20735 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20736 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20737 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20738 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20739 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20740 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20750 * @cfg {String/Object} Label for the strength meter (defaults to
20751 * 'Password strength:')
20756 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20757 * ['Weak', 'Medium', 'Strong'])
20773 initEvents: function () {
20774 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20776 if (this.el.is('input[type=password]') && Roo.isSafari) {
20777 this.el.on('keydown', this.SafariOnKeyDown, this);
20780 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20783 onRender: function (ct, position) {
20784 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20785 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20786 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20788 this.trigger.createChild({
20793 cls: 'roo-password-meter-grey col-xs-12',
20796 //width: this.meterWidth + 'px'
20800 cls: 'roo-password-meter-text'
20806 this.trigger.createChild({
20808 cls: 'roo-password-meter-container col-xs-12',
20810 //width: this.meterWidth + 'px'
20814 cls: 'roo-password-meter-grey',
20816 //width: this.meterWidth + 'px'
20822 cls: 'roo-password-meter-grey col-xs-12',
20825 //width: this.meterWidth + 'px'
20829 cls: 'roo-password-meter-text'
20835 if (this.hideTrigger) {
20836 this.trigger.setDisplayed(false);
20838 this.setSize(this.width || '', this.height || '');
20841 onDestroy: function () {
20842 if (this.trigger) {
20843 this.trigger.removeAllListeners();
20844 this.trigger.remove();
20847 this.wrap.remove();
20849 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20852 checkStrength: function () {
20853 var pwd = this.inputEl().getValue();
20854 if (pwd == this._lastPwd) {
20859 if (this.ClientSideStrongPassword(pwd)) {
20861 } else if (this.ClientSideMediumPassword(pwd)) {
20863 } else if (this.ClientSideWeakPassword(pwd)) {
20869 console.log('strength1: ' + strength);
20871 //var pm = this.trigger.child('div/div/div').dom;
20872 var pm = this.trigger.child('div/div');
20873 pm.removeClass(this.meterClass);
20874 pm.addClass(this.meterClass[strength]);
20877 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20879 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20881 this._lastPwd = pwd;
20883 reset: function () {
20884 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20886 this._lastPwd = '';
20888 var pm = this.trigger.child('div/div');
20889 pm.removeClass(this.meterClass);
20890 pm.addClass('roo-password-meter-grey');
20893 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20896 this.inputEl().dom.type='password';
20899 validateValue: function (value) {
20901 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20904 if (value.length == 0) {
20905 if (this.allowBlank) {
20906 this.clearInvalid();
20910 this.markInvalid(this.errors.PwdEmpty);
20911 this.errorMsg = this.errors.PwdEmpty;
20919 if ('[\x21-\x7e]*'.match(value)) {
20920 this.markInvalid(this.errors.PwdBadChar);
20921 this.errorMsg = this.errors.PwdBadChar;
20924 if (value.length < 6) {
20925 this.markInvalid(this.errors.PwdShort);
20926 this.errorMsg = this.errors.PwdShort;
20929 if (value.length > 16) {
20930 this.markInvalid(this.errors.PwdLong);
20931 this.errorMsg = this.errors.PwdLong;
20935 if (this.ClientSideStrongPassword(value)) {
20937 } else if (this.ClientSideMediumPassword(value)) {
20939 } else if (this.ClientSideWeakPassword(value)) {
20946 if (strength < 2) {
20947 //this.markInvalid(this.errors.TooWeak);
20948 this.errorMsg = this.errors.TooWeak;
20953 console.log('strength2: ' + strength);
20955 //var pm = this.trigger.child('div/div/div').dom;
20957 var pm = this.trigger.child('div/div');
20958 pm.removeClass(this.meterClass);
20959 pm.addClass(this.meterClass[strength]);
20961 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20963 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20965 this.errorMsg = '';
20969 CharacterSetChecks: function (type) {
20971 this.fResult = false;
20974 isctype: function (character, type) {
20975 switch (type) { //why needed break after return in js ? very odd bug
20976 case this.kCapitalLetter:
20977 if (character >= 'A' && character <= 'Z') {
20981 case this.kSmallLetter:
20982 if (character >= 'a' && character <= 'z') {
20987 if (character >= '0' && character <= '9') {
20991 case this.kPunctuation:
20992 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21002 IsLongEnough: function (pwd, size) {
21003 return !(pwd == null || isNaN(size) || pwd.length < size);
21006 SpansEnoughCharacterSets: function (word, nb) {
21007 if (!this.IsLongEnough(word, nb))
21012 var characterSetChecks = new Array(
21013 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21014 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation));
21015 for (var index = 0; index < word.length; ++index) {
21016 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21017 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21018 characterSetChecks[nCharSet].fResult = true;
21025 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21026 if (characterSetChecks[nCharSet].fResult) {
21031 if (nCharSets < nb) {
21037 ClientSideStrongPassword: function (pwd) {
21038 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21041 ClientSideMediumPassword: function (pwd) {
21042 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21045 ClientSideWeakPassword: function (pwd) {
21046 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21049 })//<script type="text/javascript">
21052 * Based Ext JS Library 1.1.1
21053 * Copyright(c) 2006-2007, Ext JS, LLC.
21059 * @class Roo.HtmlEditorCore
21060 * @extends Roo.Component
21061 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21063 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21066 Roo.HtmlEditorCore = function(config){
21069 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21074 * @event initialize
21075 * Fires when the editor is fully initialized (including the iframe)
21076 * @param {Roo.HtmlEditorCore} this
21081 * Fires when the editor is first receives the focus. Any insertion must wait
21082 * until after this event.
21083 * @param {Roo.HtmlEditorCore} this
21087 * @event beforesync
21088 * Fires before the textarea is updated with content from the editor iframe. Return false
21089 * to cancel the sync.
21090 * @param {Roo.HtmlEditorCore} this
21091 * @param {String} html
21095 * @event beforepush
21096 * Fires before the iframe editor is updated with content from the textarea. Return false
21097 * to cancel the push.
21098 * @param {Roo.HtmlEditorCore} this
21099 * @param {String} html
21104 * Fires when the textarea is updated with content from the editor iframe.
21105 * @param {Roo.HtmlEditorCore} this
21106 * @param {String} html
21111 * Fires when the iframe editor is updated with content from the textarea.
21112 * @param {Roo.HtmlEditorCore} this
21113 * @param {String} html
21118 * @event editorevent
21119 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21120 * @param {Roo.HtmlEditorCore} this
21126 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21128 // defaults : white / black...
21129 this.applyBlacklists();
21136 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21140 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21146 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21151 * @cfg {Number} height (in pixels)
21155 * @cfg {Number} width (in pixels)
21160 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21163 stylesheets: false,
21168 // private properties
21169 validationEvent : false,
21171 initialized : false,
21173 sourceEditMode : false,
21174 onFocus : Roo.emptyFn,
21176 hideMode:'offsets',
21180 // blacklist + whitelisted elements..
21187 * Protected method that will not generally be called directly. It
21188 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21189 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21191 getDocMarkup : function(){
21195 // inherit styels from page...??
21196 if (this.stylesheets === false) {
21198 Roo.get(document.head).select('style').each(function(node) {
21199 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21202 Roo.get(document.head).select('link').each(function(node) {
21203 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21206 } else if (!this.stylesheets.length) {
21208 st = '<style type="text/css">' +
21209 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21215 st += '<style type="text/css">' +
21216 'IMG { cursor: pointer } ' +
21220 return '<html><head>' + st +
21221 //<style type="text/css">' +
21222 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21224 ' </head><body class="roo-htmleditor-body"></body></html>';
21228 onRender : function(ct, position)
21231 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21232 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21235 this.el.dom.style.border = '0 none';
21236 this.el.dom.setAttribute('tabIndex', -1);
21237 this.el.addClass('x-hidden hide');
21241 if(Roo.isIE){ // fix IE 1px bogus margin
21242 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21246 this.frameId = Roo.id();
21250 var iframe = this.owner.wrap.createChild({
21252 cls: 'form-control', // bootstrap..
21254 name: this.frameId,
21255 frameBorder : 'no',
21256 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21261 this.iframe = iframe.dom;
21263 this.assignDocWin();
21265 this.doc.designMode = 'on';
21268 this.doc.write(this.getDocMarkup());
21272 var task = { // must defer to wait for browser to be ready
21274 //console.log("run task?" + this.doc.readyState);
21275 this.assignDocWin();
21276 if(this.doc.body || this.doc.readyState == 'complete'){
21278 this.doc.designMode="on";
21282 Roo.TaskMgr.stop(task);
21283 this.initEditor.defer(10, this);
21290 Roo.TaskMgr.start(task);
21295 onResize : function(w, h)
21297 Roo.log('resize: ' +w + ',' + h );
21298 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21302 if(typeof w == 'number'){
21304 this.iframe.style.width = w + 'px';
21306 if(typeof h == 'number'){
21308 this.iframe.style.height = h + 'px';
21310 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21317 * Toggles the editor between standard and source edit mode.
21318 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21320 toggleSourceEdit : function(sourceEditMode){
21322 this.sourceEditMode = sourceEditMode === true;
21324 if(this.sourceEditMode){
21326 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21329 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21330 //this.iframe.className = '';
21333 //this.setSize(this.owner.wrap.getSize());
21334 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21341 * Protected method that will not generally be called directly. If you need/want
21342 * custom HTML cleanup, this is the method you should override.
21343 * @param {String} html The HTML to be cleaned
21344 * return {String} The cleaned HTML
21346 cleanHtml : function(html){
21347 html = String(html);
21348 if(html.length > 5){
21349 if(Roo.isSafari){ // strip safari nonsense
21350 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21353 if(html == ' '){
21360 * HTML Editor -> Textarea
21361 * Protected method that will not generally be called directly. Syncs the contents
21362 * of the editor iframe with the textarea.
21364 syncValue : function(){
21365 if(this.initialized){
21366 var bd = (this.doc.body || this.doc.documentElement);
21367 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21368 var html = bd.innerHTML;
21370 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21371 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21373 html = '<div style="'+m[0]+'">' + html + '</div>';
21376 html = this.cleanHtml(html);
21377 // fix up the special chars.. normaly like back quotes in word...
21378 // however we do not want to do this with chinese..
21379 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21380 var cc = b.charCodeAt();
21382 (cc >= 0x4E00 && cc < 0xA000 ) ||
21383 (cc >= 0x3400 && cc < 0x4E00 ) ||
21384 (cc >= 0xf900 && cc < 0xfb00 )
21390 if(this.owner.fireEvent('beforesync', this, html) !== false){
21391 this.el.dom.value = html;
21392 this.owner.fireEvent('sync', this, html);
21398 * Protected method that will not generally be called directly. Pushes the value of the textarea
21399 * into the iframe editor.
21401 pushValue : function(){
21402 if(this.initialized){
21403 var v = this.el.dom.value.trim();
21405 // if(v.length < 1){
21409 if(this.owner.fireEvent('beforepush', this, v) !== false){
21410 var d = (this.doc.body || this.doc.documentElement);
21412 this.cleanUpPaste();
21413 this.el.dom.value = d.innerHTML;
21414 this.owner.fireEvent('push', this, v);
21420 deferFocus : function(){
21421 this.focus.defer(10, this);
21425 focus : function(){
21426 if(this.win && !this.sourceEditMode){
21433 assignDocWin: function()
21435 var iframe = this.iframe;
21438 this.doc = iframe.contentWindow.document;
21439 this.win = iframe.contentWindow;
21441 // if (!Roo.get(this.frameId)) {
21444 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21445 // this.win = Roo.get(this.frameId).dom.contentWindow;
21447 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21451 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21452 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21457 initEditor : function(){
21458 //console.log("INIT EDITOR");
21459 this.assignDocWin();
21463 this.doc.designMode="on";
21465 this.doc.write(this.getDocMarkup());
21468 var dbody = (this.doc.body || this.doc.documentElement);
21469 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21470 // this copies styles from the containing element into thsi one..
21471 // not sure why we need all of this..
21472 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21474 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21475 //ss['background-attachment'] = 'fixed'; // w3c
21476 dbody.bgProperties = 'fixed'; // ie
21477 //Roo.DomHelper.applyStyles(dbody, ss);
21478 Roo.EventManager.on(this.doc, {
21479 //'mousedown': this.onEditorEvent,
21480 'mouseup': this.onEditorEvent,
21481 'dblclick': this.onEditorEvent,
21482 'click': this.onEditorEvent,
21483 'keyup': this.onEditorEvent,
21488 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21490 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21491 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21493 this.initialized = true;
21495 this.owner.fireEvent('initialize', this);
21500 onDestroy : function(){
21506 //for (var i =0; i < this.toolbars.length;i++) {
21507 // // fixme - ask toolbars for heights?
21508 // this.toolbars[i].onDestroy();
21511 //this.wrap.dom.innerHTML = '';
21512 //this.wrap.remove();
21517 onFirstFocus : function(){
21519 this.assignDocWin();
21522 this.activated = true;
21525 if(Roo.isGecko){ // prevent silly gecko errors
21527 var s = this.win.getSelection();
21528 if(!s.focusNode || s.focusNode.nodeType != 3){
21529 var r = s.getRangeAt(0);
21530 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21535 this.execCmd('useCSS', true);
21536 this.execCmd('styleWithCSS', false);
21539 this.owner.fireEvent('activate', this);
21543 adjustFont: function(btn){
21544 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21545 //if(Roo.isSafari){ // safari
21548 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21549 if(Roo.isSafari){ // safari
21550 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21551 v = (v < 10) ? 10 : v;
21552 v = (v > 48) ? 48 : v;
21553 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21558 v = Math.max(1, v+adjust);
21560 this.execCmd('FontSize', v );
21563 onEditorEvent : function(e)
21565 this.owner.fireEvent('editorevent', this, e);
21566 // this.updateToolbar();
21567 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21570 insertTag : function(tg)
21572 // could be a bit smarter... -> wrap the current selected tRoo..
21573 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21575 range = this.createRange(this.getSelection());
21576 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21577 wrappingNode.appendChild(range.extractContents());
21578 range.insertNode(wrappingNode);
21585 this.execCmd("formatblock", tg);
21589 insertText : function(txt)
21593 var range = this.createRange();
21594 range.deleteContents();
21595 //alert(Sender.getAttribute('label'));
21597 range.insertNode(this.doc.createTextNode(txt));
21603 * Executes a Midas editor command on the editor document and performs necessary focus and
21604 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21605 * @param {String} cmd The Midas command
21606 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21608 relayCmd : function(cmd, value){
21610 this.execCmd(cmd, value);
21611 this.owner.fireEvent('editorevent', this);
21612 //this.updateToolbar();
21613 this.owner.deferFocus();
21617 * Executes a Midas editor command directly on the editor document.
21618 * For visual commands, you should use {@link #relayCmd} instead.
21619 * <b>This should only be called after the editor is initialized.</b>
21620 * @param {String} cmd The Midas command
21621 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21623 execCmd : function(cmd, value){
21624 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21631 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21633 * @param {String} text | dom node..
21635 insertAtCursor : function(text)
21640 if(!this.activated){
21646 var r = this.doc.selection.createRange();
21657 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21661 // from jquery ui (MIT licenced)
21663 var win = this.win;
21665 if (win.getSelection && win.getSelection().getRangeAt) {
21666 range = win.getSelection().getRangeAt(0);
21667 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21668 range.insertNode(node);
21669 } else if (win.document.selection && win.document.selection.createRange) {
21670 // no firefox support
21671 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21672 win.document.selection.createRange().pasteHTML(txt);
21674 // no firefox support
21675 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21676 this.execCmd('InsertHTML', txt);
21685 mozKeyPress : function(e){
21687 var c = e.getCharCode(), cmd;
21690 c = String.fromCharCode(c).toLowerCase();
21704 this.cleanUpPaste.defer(100, this);
21712 e.preventDefault();
21720 fixKeys : function(){ // load time branching for fastest keydown performance
21722 return function(e){
21723 var k = e.getKey(), r;
21726 r = this.doc.selection.createRange();
21729 r.pasteHTML('    ');
21736 r = this.doc.selection.createRange();
21738 var target = r.parentElement();
21739 if(!target || target.tagName.toLowerCase() != 'li'){
21741 r.pasteHTML('<br />');
21747 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21748 this.cleanUpPaste.defer(100, this);
21754 }else if(Roo.isOpera){
21755 return function(e){
21756 var k = e.getKey();
21760 this.execCmd('InsertHTML','    ');
21763 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21764 this.cleanUpPaste.defer(100, this);
21769 }else if(Roo.isSafari){
21770 return function(e){
21771 var k = e.getKey();
21775 this.execCmd('InsertText','\t');
21779 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21780 this.cleanUpPaste.defer(100, this);
21788 getAllAncestors: function()
21790 var p = this.getSelectedNode();
21793 a.push(p); // push blank onto stack..
21794 p = this.getParentElement();
21798 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21802 a.push(this.doc.body);
21806 lastSelNode : false,
21809 getSelection : function()
21811 this.assignDocWin();
21812 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21815 getSelectedNode: function()
21817 // this may only work on Gecko!!!
21819 // should we cache this!!!!
21824 var range = this.createRange(this.getSelection()).cloneRange();
21827 var parent = range.parentElement();
21829 var testRange = range.duplicate();
21830 testRange.moveToElementText(parent);
21831 if (testRange.inRange(range)) {
21834 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21837 parent = parent.parentElement;
21842 // is ancestor a text element.
21843 var ac = range.commonAncestorContainer;
21844 if (ac.nodeType == 3) {
21845 ac = ac.parentNode;
21848 var ar = ac.childNodes;
21851 var other_nodes = [];
21852 var has_other_nodes = false;
21853 for (var i=0;i<ar.length;i++) {
21854 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21857 // fullly contained node.
21859 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21864 // probably selected..
21865 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21866 other_nodes.push(ar[i]);
21870 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21875 has_other_nodes = true;
21877 if (!nodes.length && other_nodes.length) {
21878 nodes= other_nodes;
21880 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21886 createRange: function(sel)
21888 // this has strange effects when using with
21889 // top toolbar - not sure if it's a great idea.
21890 //this.editor.contentWindow.focus();
21891 if (typeof sel != "undefined") {
21893 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21895 return this.doc.createRange();
21898 return this.doc.createRange();
21901 getParentElement: function()
21904 this.assignDocWin();
21905 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21907 var range = this.createRange(sel);
21910 var p = range.commonAncestorContainer;
21911 while (p.nodeType == 3) { // text node
21922 * Range intersection.. the hard stuff...
21926 * [ -- selected range --- ]
21930 * if end is before start or hits it. fail.
21931 * if start is after end or hits it fail.
21933 * if either hits (but other is outside. - then it's not
21939 // @see http://www.thismuchiknow.co.uk/?p=64.
21940 rangeIntersectsNode : function(range, node)
21942 var nodeRange = node.ownerDocument.createRange();
21944 nodeRange.selectNode(node);
21946 nodeRange.selectNodeContents(node);
21949 var rangeStartRange = range.cloneRange();
21950 rangeStartRange.collapse(true);
21952 var rangeEndRange = range.cloneRange();
21953 rangeEndRange.collapse(false);
21955 var nodeStartRange = nodeRange.cloneRange();
21956 nodeStartRange.collapse(true);
21958 var nodeEndRange = nodeRange.cloneRange();
21959 nodeEndRange.collapse(false);
21961 return rangeStartRange.compareBoundaryPoints(
21962 Range.START_TO_START, nodeEndRange) == -1 &&
21963 rangeEndRange.compareBoundaryPoints(
21964 Range.START_TO_START, nodeStartRange) == 1;
21968 rangeCompareNode : function(range, node)
21970 var nodeRange = node.ownerDocument.createRange();
21972 nodeRange.selectNode(node);
21974 nodeRange.selectNodeContents(node);
21978 range.collapse(true);
21980 nodeRange.collapse(true);
21982 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21983 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21985 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21987 var nodeIsBefore = ss == 1;
21988 var nodeIsAfter = ee == -1;
21990 if (nodeIsBefore && nodeIsAfter) {
21993 if (!nodeIsBefore && nodeIsAfter) {
21994 return 1; //right trailed.
21997 if (nodeIsBefore && !nodeIsAfter) {
21998 return 2; // left trailed.
22004 // private? - in a new class?
22005 cleanUpPaste : function()
22007 // cleans up the whole document..
22008 Roo.log('cleanuppaste');
22010 this.cleanUpChildren(this.doc.body);
22011 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22012 if (clean != this.doc.body.innerHTML) {
22013 this.doc.body.innerHTML = clean;
22018 cleanWordChars : function(input) {// change the chars to hex code
22019 var he = Roo.HtmlEditorCore;
22021 var output = input;
22022 Roo.each(he.swapCodes, function(sw) {
22023 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22025 output = output.replace(swapper, sw[1]);
22032 cleanUpChildren : function (n)
22034 if (!n.childNodes.length) {
22037 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22038 this.cleanUpChild(n.childNodes[i]);
22045 cleanUpChild : function (node)
22048 //console.log(node);
22049 if (node.nodeName == "#text") {
22050 // clean up silly Windows -- stuff?
22053 if (node.nodeName == "#comment") {
22054 node.parentNode.removeChild(node);
22055 // clean up silly Windows -- stuff?
22058 var lcname = node.tagName.toLowerCase();
22059 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22060 // whitelist of tags..
22062 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22064 node.parentNode.removeChild(node);
22069 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22071 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22072 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22074 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22075 // remove_keep_children = true;
22078 if (remove_keep_children) {
22079 this.cleanUpChildren(node);
22080 // inserts everything just before this node...
22081 while (node.childNodes.length) {
22082 var cn = node.childNodes[0];
22083 node.removeChild(cn);
22084 node.parentNode.insertBefore(cn, node);
22086 node.parentNode.removeChild(node);
22090 if (!node.attributes || !node.attributes.length) {
22091 this.cleanUpChildren(node);
22095 function cleanAttr(n,v)
22098 if (v.match(/^\./) || v.match(/^\//)) {
22101 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22104 if (v.match(/^#/)) {
22107 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22108 node.removeAttribute(n);
22112 var cwhite = this.cwhite;
22113 var cblack = this.cblack;
22115 function cleanStyle(n,v)
22117 if (v.match(/expression/)) { //XSS?? should we even bother..
22118 node.removeAttribute(n);
22122 var parts = v.split(/;/);
22125 Roo.each(parts, function(p) {
22126 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22130 var l = p.split(':').shift().replace(/\s+/g,'');
22131 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22133 if ( cwhite.length && cblack.indexOf(l) > -1) {
22134 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22135 //node.removeAttribute(n);
22139 // only allow 'c whitelisted system attributes'
22140 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22141 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22142 //node.removeAttribute(n);
22152 if (clean.length) {
22153 node.setAttribute(n, clean.join(';'));
22155 node.removeAttribute(n);
22161 for (var i = node.attributes.length-1; i > -1 ; i--) {
22162 var a = node.attributes[i];
22165 if (a.name.toLowerCase().substr(0,2)=='on') {
22166 node.removeAttribute(a.name);
22169 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22170 node.removeAttribute(a.name);
22173 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22174 cleanAttr(a.name,a.value); // fixme..
22177 if (a.name == 'style') {
22178 cleanStyle(a.name,a.value);
22181 /// clean up MS crap..
22182 // tecnically this should be a list of valid class'es..
22185 if (a.name == 'class') {
22186 if (a.value.match(/^Mso/)) {
22187 node.className = '';
22190 if (a.value.match(/body/)) {
22191 node.className = '';
22202 this.cleanUpChildren(node);
22208 * Clean up MS wordisms...
22210 cleanWord : function(node)
22215 this.cleanWord(this.doc.body);
22218 if (node.nodeName == "#text") {
22219 // clean up silly Windows -- stuff?
22222 if (node.nodeName == "#comment") {
22223 node.parentNode.removeChild(node);
22224 // clean up silly Windows -- stuff?
22228 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22229 node.parentNode.removeChild(node);
22233 // remove - but keep children..
22234 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22235 while (node.childNodes.length) {
22236 var cn = node.childNodes[0];
22237 node.removeChild(cn);
22238 node.parentNode.insertBefore(cn, node);
22240 node.parentNode.removeChild(node);
22241 this.iterateChildren(node, this.cleanWord);
22245 if (node.className.length) {
22247 var cn = node.className.split(/\W+/);
22249 Roo.each(cn, function(cls) {
22250 if (cls.match(/Mso[a-zA-Z]+/)) {
22255 node.className = cna.length ? cna.join(' ') : '';
22257 node.removeAttribute("class");
22261 if (node.hasAttribute("lang")) {
22262 node.removeAttribute("lang");
22265 if (node.hasAttribute("style")) {
22267 var styles = node.getAttribute("style").split(";");
22269 Roo.each(styles, function(s) {
22270 if (!s.match(/:/)) {
22273 var kv = s.split(":");
22274 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22277 // what ever is left... we allow.
22280 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22281 if (!nstyle.length) {
22282 node.removeAttribute('style');
22285 this.iterateChildren(node, this.cleanWord);
22291 * iterateChildren of a Node, calling fn each time, using this as the scole..
22292 * @param {DomNode} node node to iterate children of.
22293 * @param {Function} fn method of this class to call on each item.
22295 iterateChildren : function(node, fn)
22297 if (!node.childNodes.length) {
22300 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22301 fn.call(this, node.childNodes[i])
22307 * cleanTableWidths.
22309 * Quite often pasting from word etc.. results in tables with column and widths.
22310 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22313 cleanTableWidths : function(node)
22318 this.cleanTableWidths(this.doc.body);
22323 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22326 Roo.log(node.tagName);
22327 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22328 this.iterateChildren(node, this.cleanTableWidths);
22331 if (node.hasAttribute('width')) {
22332 node.removeAttribute('width');
22336 if (node.hasAttribute("style")) {
22339 var styles = node.getAttribute("style").split(";");
22341 Roo.each(styles, function(s) {
22342 if (!s.match(/:/)) {
22345 var kv = s.split(":");
22346 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22349 // what ever is left... we allow.
22352 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22353 if (!nstyle.length) {
22354 node.removeAttribute('style');
22358 this.iterateChildren(node, this.cleanTableWidths);
22366 domToHTML : function(currentElement, depth, nopadtext) {
22368 depth = depth || 0;
22369 nopadtext = nopadtext || false;
22371 if (!currentElement) {
22372 return this.domToHTML(this.doc.body);
22375 //Roo.log(currentElement);
22377 var allText = false;
22378 var nodeName = currentElement.nodeName;
22379 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22381 if (nodeName == '#text') {
22383 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22388 if (nodeName != 'BODY') {
22391 // Prints the node tagName, such as <A>, <IMG>, etc
22394 for(i = 0; i < currentElement.attributes.length;i++) {
22396 var aname = currentElement.attributes.item(i).name;
22397 if (!currentElement.attributes.item(i).value.length) {
22400 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22403 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22412 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22415 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22420 // Traverse the tree
22422 var currentElementChild = currentElement.childNodes.item(i);
22423 var allText = true;
22424 var innerHTML = '';
22426 while (currentElementChild) {
22427 // Formatting code (indent the tree so it looks nice on the screen)
22428 var nopad = nopadtext;
22429 if (lastnode == 'SPAN') {
22433 if (currentElementChild.nodeName == '#text') {
22434 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22435 toadd = nopadtext ? toadd : toadd.trim();
22436 if (!nopad && toadd.length > 80) {
22437 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22439 innerHTML += toadd;
22442 currentElementChild = currentElement.childNodes.item(i);
22448 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22450 // Recursively traverse the tree structure of the child node
22451 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22452 lastnode = currentElementChild.nodeName;
22454 currentElementChild=currentElement.childNodes.item(i);
22460 // The remaining code is mostly for formatting the tree
22461 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22466 ret+= "</"+tagName+">";
22472 applyBlacklists : function()
22474 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22475 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22479 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22480 if (b.indexOf(tag) > -1) {
22483 this.white.push(tag);
22487 Roo.each(w, function(tag) {
22488 if (b.indexOf(tag) > -1) {
22491 if (this.white.indexOf(tag) > -1) {
22494 this.white.push(tag);
22499 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22500 if (w.indexOf(tag) > -1) {
22503 this.black.push(tag);
22507 Roo.each(b, function(tag) {
22508 if (w.indexOf(tag) > -1) {
22511 if (this.black.indexOf(tag) > -1) {
22514 this.black.push(tag);
22519 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22520 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22524 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22525 if (b.indexOf(tag) > -1) {
22528 this.cwhite.push(tag);
22532 Roo.each(w, function(tag) {
22533 if (b.indexOf(tag) > -1) {
22536 if (this.cwhite.indexOf(tag) > -1) {
22539 this.cwhite.push(tag);
22544 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22545 if (w.indexOf(tag) > -1) {
22548 this.cblack.push(tag);
22552 Roo.each(b, function(tag) {
22553 if (w.indexOf(tag) > -1) {
22556 if (this.cblack.indexOf(tag) > -1) {
22559 this.cblack.push(tag);
22564 setStylesheets : function(stylesheets)
22566 if(typeof(stylesheets) == 'string'){
22567 Roo.get(this.iframe.contentDocument.head).createChild({
22569 rel : 'stylesheet',
22578 Roo.each(stylesheets, function(s) {
22583 Roo.get(_this.iframe.contentDocument.head).createChild({
22585 rel : 'stylesheet',
22594 removeStylesheets : function()
22598 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22603 // hide stuff that is not compatible
22617 * @event specialkey
22621 * @cfg {String} fieldClass @hide
22624 * @cfg {String} focusClass @hide
22627 * @cfg {String} autoCreate @hide
22630 * @cfg {String} inputType @hide
22633 * @cfg {String} invalidClass @hide
22636 * @cfg {String} invalidText @hide
22639 * @cfg {String} msgFx @hide
22642 * @cfg {String} validateOnBlur @hide
22646 Roo.HtmlEditorCore.white = [
22647 'area', 'br', 'img', 'input', 'hr', 'wbr',
22649 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22650 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22651 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22652 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22653 'table', 'ul', 'xmp',
22655 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22658 'dir', 'menu', 'ol', 'ul', 'dl',
22664 Roo.HtmlEditorCore.black = [
22665 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22667 'base', 'basefont', 'bgsound', 'blink', 'body',
22668 'frame', 'frameset', 'head', 'html', 'ilayer',
22669 'iframe', 'layer', 'link', 'meta', 'object',
22670 'script', 'style' ,'title', 'xml' // clean later..
22672 Roo.HtmlEditorCore.clean = [
22673 'script', 'style', 'title', 'xml'
22675 Roo.HtmlEditorCore.remove = [
22680 Roo.HtmlEditorCore.ablack = [
22684 Roo.HtmlEditorCore.aclean = [
22685 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22689 Roo.HtmlEditorCore.pwhite= [
22690 'http', 'https', 'mailto'
22693 // white listed style attributes.
22694 Roo.HtmlEditorCore.cwhite= [
22695 // 'text-align', /// default is to allow most things..
22701 // black listed style attributes.
22702 Roo.HtmlEditorCore.cblack= [
22703 // 'font-size' -- this can be set by the project
22707 Roo.HtmlEditorCore.swapCodes =[
22726 * @class Roo.bootstrap.HtmlEditor
22727 * @extends Roo.bootstrap.TextArea
22728 * Bootstrap HtmlEditor class
22731 * Create a new HtmlEditor
22732 * @param {Object} config The config object
22735 Roo.bootstrap.HtmlEditor = function(config){
22736 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22737 if (!this.toolbars) {
22738 this.toolbars = [];
22740 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22743 * @event initialize
22744 * Fires when the editor is fully initialized (including the iframe)
22745 * @param {HtmlEditor} this
22750 * Fires when the editor is first receives the focus. Any insertion must wait
22751 * until after this event.
22752 * @param {HtmlEditor} this
22756 * @event beforesync
22757 * Fires before the textarea is updated with content from the editor iframe. Return false
22758 * to cancel the sync.
22759 * @param {HtmlEditor} this
22760 * @param {String} html
22764 * @event beforepush
22765 * Fires before the iframe editor is updated with content from the textarea. Return false
22766 * to cancel the push.
22767 * @param {HtmlEditor} this
22768 * @param {String} html
22773 * Fires when the textarea is updated with content from the editor iframe.
22774 * @param {HtmlEditor} this
22775 * @param {String} html
22780 * Fires when the iframe editor is updated with content from the textarea.
22781 * @param {HtmlEditor} this
22782 * @param {String} html
22786 * @event editmodechange
22787 * Fires when the editor switches edit modes
22788 * @param {HtmlEditor} this
22789 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22791 editmodechange: true,
22793 * @event editorevent
22794 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22795 * @param {HtmlEditor} this
22799 * @event firstfocus
22800 * Fires when on first focus - needed by toolbars..
22801 * @param {HtmlEditor} this
22806 * Auto save the htmlEditor value as a file into Events
22807 * @param {HtmlEditor} this
22811 * @event savedpreview
22812 * preview the saved version of htmlEditor
22813 * @param {HtmlEditor} this
22820 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22824 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22829 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22834 * @cfg {Number} height (in pixels)
22838 * @cfg {Number} width (in pixels)
22843 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22846 stylesheets: false,
22851 // private properties
22852 validationEvent : false,
22854 initialized : false,
22857 onFocus : Roo.emptyFn,
22859 hideMode:'offsets',
22862 tbContainer : false,
22864 toolbarContainer :function() {
22865 return this.wrap.select('.x-html-editor-tb',true).first();
22869 * Protected method that will not generally be called directly. It
22870 * is called when the editor creates its toolbar. Override this method if you need to
22871 * add custom toolbar buttons.
22872 * @param {HtmlEditor} editor
22874 createToolbar : function(){
22876 Roo.log("create toolbars");
22878 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22879 this.toolbars[0].render(this.toolbarContainer());
22883 // if (!editor.toolbars || !editor.toolbars.length) {
22884 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22887 // for (var i =0 ; i < editor.toolbars.length;i++) {
22888 // editor.toolbars[i] = Roo.factory(
22889 // typeof(editor.toolbars[i]) == 'string' ?
22890 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22891 // Roo.bootstrap.HtmlEditor);
22892 // editor.toolbars[i].init(editor);
22898 onRender : function(ct, position)
22900 // Roo.log("Call onRender: " + this.xtype);
22902 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22904 this.wrap = this.inputEl().wrap({
22905 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22908 this.editorcore.onRender(ct, position);
22910 if (this.resizable) {
22911 this.resizeEl = new Roo.Resizable(this.wrap, {
22915 minHeight : this.height,
22916 height: this.height,
22917 handles : this.resizable,
22920 resize : function(r, w, h) {
22921 _t.onResize(w,h); // -something
22927 this.createToolbar(this);
22930 if(!this.width && this.resizable){
22931 this.setSize(this.wrap.getSize());
22933 if (this.resizeEl) {
22934 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22935 // should trigger onReize..
22941 onResize : function(w, h)
22943 Roo.log('resize: ' +w + ',' + h );
22944 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22948 if(this.inputEl() ){
22949 if(typeof w == 'number'){
22950 var aw = w - this.wrap.getFrameWidth('lr');
22951 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22954 if(typeof h == 'number'){
22955 var tbh = -11; // fixme it needs to tool bar size!
22956 for (var i =0; i < this.toolbars.length;i++) {
22957 // fixme - ask toolbars for heights?
22958 tbh += this.toolbars[i].el.getHeight();
22959 //if (this.toolbars[i].footer) {
22960 // tbh += this.toolbars[i].footer.el.getHeight();
22968 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22969 ah -= 5; // knock a few pixes off for look..
22970 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22974 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22975 this.editorcore.onResize(ew,eh);
22980 * Toggles the editor between standard and source edit mode.
22981 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22983 toggleSourceEdit : function(sourceEditMode)
22985 this.editorcore.toggleSourceEdit(sourceEditMode);
22987 if(this.editorcore.sourceEditMode){
22988 Roo.log('editor - showing textarea');
22991 // Roo.log(this.syncValue());
22993 this.inputEl().removeClass(['hide', 'x-hidden']);
22994 this.inputEl().dom.removeAttribute('tabIndex');
22995 this.inputEl().focus();
22997 Roo.log('editor - hiding textarea');
22999 // Roo.log(this.pushValue());
23002 this.inputEl().addClass(['hide', 'x-hidden']);
23003 this.inputEl().dom.setAttribute('tabIndex', -1);
23004 //this.deferFocus();
23007 if(this.resizable){
23008 this.setSize(this.wrap.getSize());
23011 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23014 // private (for BoxComponent)
23015 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23017 // private (for BoxComponent)
23018 getResizeEl : function(){
23022 // private (for BoxComponent)
23023 getPositionEl : function(){
23028 initEvents : function(){
23029 this.originalValue = this.getValue();
23033 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23036 // markInvalid : Roo.emptyFn,
23038 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23041 // clearInvalid : Roo.emptyFn,
23043 setValue : function(v){
23044 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23045 this.editorcore.pushValue();
23050 deferFocus : function(){
23051 this.focus.defer(10, this);
23055 focus : function(){
23056 this.editorcore.focus();
23062 onDestroy : function(){
23068 for (var i =0; i < this.toolbars.length;i++) {
23069 // fixme - ask toolbars for heights?
23070 this.toolbars[i].onDestroy();
23073 this.wrap.dom.innerHTML = '';
23074 this.wrap.remove();
23079 onFirstFocus : function(){
23080 //Roo.log("onFirstFocus");
23081 this.editorcore.onFirstFocus();
23082 for (var i =0; i < this.toolbars.length;i++) {
23083 this.toolbars[i].onFirstFocus();
23089 syncValue : function()
23091 this.editorcore.syncValue();
23094 pushValue : function()
23096 this.editorcore.pushValue();
23100 // hide stuff that is not compatible
23114 * @event specialkey
23118 * @cfg {String} fieldClass @hide
23121 * @cfg {String} focusClass @hide
23124 * @cfg {String} autoCreate @hide
23127 * @cfg {String} inputType @hide
23130 * @cfg {String} invalidClass @hide
23133 * @cfg {String} invalidText @hide
23136 * @cfg {String} msgFx @hide
23139 * @cfg {String} validateOnBlur @hide
23148 Roo.namespace('Roo.bootstrap.htmleditor');
23150 * @class Roo.bootstrap.HtmlEditorToolbar1
23155 new Roo.bootstrap.HtmlEditor({
23158 new Roo.bootstrap.HtmlEditorToolbar1({
23159 disable : { fonts: 1 , format: 1, ..., ... , ...],
23165 * @cfg {Object} disable List of elements to disable..
23166 * @cfg {Array} btns List of additional buttons.
23170 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23173 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23176 Roo.apply(this, config);
23178 // default disabled, based on 'good practice'..
23179 this.disable = this.disable || {};
23180 Roo.applyIf(this.disable, {
23183 specialElements : true
23185 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23187 this.editor = config.editor;
23188 this.editorcore = config.editor.editorcore;
23190 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23192 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23193 // dont call parent... till later.
23195 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23200 editorcore : false,
23205 "h1","h2","h3","h4","h5","h6",
23207 "abbr", "acronym", "address", "cite", "samp", "var",
23211 onRender : function(ct, position)
23213 // Roo.log("Call onRender: " + this.xtype);
23215 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23217 this.el.dom.style.marginBottom = '0';
23219 var editorcore = this.editorcore;
23220 var editor= this.editor;
23223 var btn = function(id,cmd , toggle, handler){
23225 var event = toggle ? 'toggle' : 'click';
23230 xns: Roo.bootstrap,
23233 enableToggle:toggle !== false,
23235 pressed : toggle ? false : null,
23238 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23239 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23248 xns: Roo.bootstrap,
23249 glyphicon : 'font',
23253 xns: Roo.bootstrap,
23257 Roo.each(this.formats, function(f) {
23258 style.menu.items.push({
23260 xns: Roo.bootstrap,
23261 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23266 editorcore.insertTag(this.tagname);
23273 children.push(style);
23276 btn('bold',false,true);
23277 btn('italic',false,true);
23278 btn('align-left', 'justifyleft',true);
23279 btn('align-center', 'justifycenter',true);
23280 btn('align-right' , 'justifyright',true);
23281 btn('link', false, false, function(btn) {
23282 //Roo.log("create link?");
23283 var url = prompt(this.createLinkText, this.defaultLinkValue);
23284 if(url && url != 'http:/'+'/'){
23285 this.editorcore.relayCmd('createlink', url);
23288 btn('list','insertunorderedlist',true);
23289 btn('pencil', false,true, function(btn){
23292 this.toggleSourceEdit(btn.pressed);
23298 xns: Roo.bootstrap,
23303 xns: Roo.bootstrap,
23308 cog.menu.items.push({
23310 xns: Roo.bootstrap,
23311 html : Clean styles,
23316 editorcore.insertTag(this.tagname);
23325 this.xtype = 'NavSimplebar';
23327 for(var i=0;i< children.length;i++) {
23329 this.buttons.add(this.addxtypeChild(children[i]));
23333 editor.on('editorevent', this.updateToolbar, this);
23335 onBtnClick : function(id)
23337 this.editorcore.relayCmd(id);
23338 this.editorcore.focus();
23342 * Protected method that will not generally be called directly. It triggers
23343 * a toolbar update by reading the markup state of the current selection in the editor.
23345 updateToolbar: function(){
23347 if(!this.editorcore.activated){
23348 this.editor.onFirstFocus(); // is this neeed?
23352 var btns = this.buttons;
23353 var doc = this.editorcore.doc;
23354 btns.get('bold').setActive(doc.queryCommandState('bold'));
23355 btns.get('italic').setActive(doc.queryCommandState('italic'));
23356 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23358 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23359 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23360 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23362 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23363 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23366 var ans = this.editorcore.getAllAncestors();
23367 if (this.formatCombo) {
23370 var store = this.formatCombo.store;
23371 this.formatCombo.setValue("");
23372 for (var i =0; i < ans.length;i++) {
23373 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23375 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23383 // hides menus... - so this cant be on a menu...
23384 Roo.bootstrap.MenuMgr.hideAll();
23386 Roo.bootstrap.MenuMgr.hideAll();
23387 //this.editorsyncValue();
23389 onFirstFocus: function() {
23390 this.buttons.each(function(item){
23394 toggleSourceEdit : function(sourceEditMode){
23397 if(sourceEditMode){
23398 Roo.log("disabling buttons");
23399 this.buttons.each( function(item){
23400 if(item.cmd != 'pencil'){
23406 Roo.log("enabling buttons");
23407 if(this.editorcore.initialized){
23408 this.buttons.each( function(item){
23414 Roo.log("calling toggole on editor");
23415 // tell the editor that it's been pressed..
23416 this.editor.toggleSourceEdit(sourceEditMode);
23426 * @class Roo.bootstrap.Table.AbstractSelectionModel
23427 * @extends Roo.util.Observable
23428 * Abstract base class for grid SelectionModels. It provides the interface that should be
23429 * implemented by descendant classes. This class should not be directly instantiated.
23432 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23433 this.locked = false;
23434 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23438 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23439 /** @ignore Called by the grid automatically. Do not call directly. */
23440 init : function(grid){
23446 * Locks the selections.
23449 this.locked = true;
23453 * Unlocks the selections.
23455 unlock : function(){
23456 this.locked = false;
23460 * Returns true if the selections are locked.
23461 * @return {Boolean}
23463 isLocked : function(){
23464 return this.locked;
23468 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23469 * @class Roo.bootstrap.Table.RowSelectionModel
23470 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23471 * It supports multiple selections and keyboard selection/navigation.
23473 * @param {Object} config
23476 Roo.bootstrap.Table.RowSelectionModel = function(config){
23477 Roo.apply(this, config);
23478 this.selections = new Roo.util.MixedCollection(false, function(o){
23483 this.lastActive = false;
23487 * @event selectionchange
23488 * Fires when the selection changes
23489 * @param {SelectionModel} this
23491 "selectionchange" : true,
23493 * @event afterselectionchange
23494 * Fires after the selection changes (eg. by key press or clicking)
23495 * @param {SelectionModel} this
23497 "afterselectionchange" : true,
23499 * @event beforerowselect
23500 * Fires when a row is selected being selected, return false to cancel.
23501 * @param {SelectionModel} this
23502 * @param {Number} rowIndex The selected index
23503 * @param {Boolean} keepExisting False if other selections will be cleared
23505 "beforerowselect" : true,
23508 * Fires when a row is selected.
23509 * @param {SelectionModel} this
23510 * @param {Number} rowIndex The selected index
23511 * @param {Roo.data.Record} r The record
23513 "rowselect" : true,
23515 * @event rowdeselect
23516 * Fires when a row is deselected.
23517 * @param {SelectionModel} this
23518 * @param {Number} rowIndex The selected index
23520 "rowdeselect" : true
23522 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23523 this.locked = false;
23526 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23528 * @cfg {Boolean} singleSelect
23529 * True to allow selection of only one row at a time (defaults to false)
23531 singleSelect : false,
23534 initEvents : function()
23537 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23538 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23539 //}else{ // allow click to work like normal
23540 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23542 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23543 this.grid.on("rowclick", this.handleMouseDown, this);
23545 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23546 "up" : function(e){
23548 this.selectPrevious(e.shiftKey);
23549 }else if(this.last !== false && this.lastActive !== false){
23550 var last = this.last;
23551 this.selectRange(this.last, this.lastActive-1);
23552 this.grid.getView().focusRow(this.lastActive);
23553 if(last !== false){
23557 this.selectFirstRow();
23559 this.fireEvent("afterselectionchange", this);
23561 "down" : function(e){
23563 this.selectNext(e.shiftKey);
23564 }else if(this.last !== false && this.lastActive !== false){
23565 var last = this.last;
23566 this.selectRange(this.last, this.lastActive+1);
23567 this.grid.getView().focusRow(this.lastActive);
23568 if(last !== false){
23572 this.selectFirstRow();
23574 this.fireEvent("afterselectionchange", this);
23578 this.grid.store.on('load', function(){
23579 this.selections.clear();
23582 var view = this.grid.view;
23583 view.on("refresh", this.onRefresh, this);
23584 view.on("rowupdated", this.onRowUpdated, this);
23585 view.on("rowremoved", this.onRemove, this);
23590 onRefresh : function()
23592 var ds = this.grid.store, i, v = this.grid.view;
23593 var s = this.selections;
23594 s.each(function(r){
23595 if((i = ds.indexOfId(r.id)) != -1){
23604 onRemove : function(v, index, r){
23605 this.selections.remove(r);
23609 onRowUpdated : function(v, index, r){
23610 if(this.isSelected(r)){
23611 v.onRowSelect(index);
23617 * @param {Array} records The records to select
23618 * @param {Boolean} keepExisting (optional) True to keep existing selections
23620 selectRecords : function(records, keepExisting)
23623 this.clearSelections();
23625 var ds = this.grid.store;
23626 for(var i = 0, len = records.length; i < len; i++){
23627 this.selectRow(ds.indexOf(records[i]), true);
23632 * Gets the number of selected rows.
23635 getCount : function(){
23636 return this.selections.length;
23640 * Selects the first row in the grid.
23642 selectFirstRow : function(){
23647 * Select the last row.
23648 * @param {Boolean} keepExisting (optional) True to keep existing selections
23650 selectLastRow : function(keepExisting){
23651 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23652 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23656 * Selects the row immediately following the last selected row.
23657 * @param {Boolean} keepExisting (optional) True to keep existing selections
23659 selectNext : function(keepExisting)
23661 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23662 this.selectRow(this.last+1, keepExisting);
23663 this.grid.getView().focusRow(this.last);
23668 * Selects the row that precedes the last selected row.
23669 * @param {Boolean} keepExisting (optional) True to keep existing selections
23671 selectPrevious : function(keepExisting){
23673 this.selectRow(this.last-1, keepExisting);
23674 this.grid.getView().focusRow(this.last);
23679 * Returns the selected records
23680 * @return {Array} Array of selected records
23682 getSelections : function(){
23683 return [].concat(this.selections.items);
23687 * Returns the first selected record.
23690 getSelected : function(){
23691 return this.selections.itemAt(0);
23696 * Clears all selections.
23698 clearSelections : function(fast)
23704 var ds = this.grid.store;
23705 var s = this.selections;
23706 s.each(function(r){
23707 this.deselectRow(ds.indexOfId(r.id));
23711 this.selections.clear();
23718 * Selects all rows.
23720 selectAll : function(){
23724 this.selections.clear();
23725 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23726 this.selectRow(i, true);
23731 * Returns True if there is a selection.
23732 * @return {Boolean}
23734 hasSelection : function(){
23735 return this.selections.length > 0;
23739 * Returns True if the specified row is selected.
23740 * @param {Number/Record} record The record or index of the record to check
23741 * @return {Boolean}
23743 isSelected : function(index){
23744 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23745 return (r && this.selections.key(r.id) ? true : false);
23749 * Returns True if the specified record id is selected.
23750 * @param {String} id The id of record to check
23751 * @return {Boolean}
23753 isIdSelected : function(id){
23754 return (this.selections.key(id) ? true : false);
23759 handleMouseDBClick : function(e, t){
23763 handleMouseDown : function(e, t)
23765 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23766 if(this.isLocked() || rowIndex < 0 ){
23769 if(e.shiftKey && this.last !== false){
23770 var last = this.last;
23771 this.selectRange(last, rowIndex, e.ctrlKey);
23772 this.last = last; // reset the last
23776 var isSelected = this.isSelected(rowIndex);
23777 //Roo.log("select row:" + rowIndex);
23779 this.deselectRow(rowIndex);
23781 this.selectRow(rowIndex, true);
23785 if(e.button !== 0 && isSelected){
23786 alert('rowIndex 2: ' + rowIndex);
23787 view.focusRow(rowIndex);
23788 }else if(e.ctrlKey && isSelected){
23789 this.deselectRow(rowIndex);
23790 }else if(!isSelected){
23791 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23792 view.focusRow(rowIndex);
23796 this.fireEvent("afterselectionchange", this);
23799 handleDragableRowClick : function(grid, rowIndex, e)
23801 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23802 this.selectRow(rowIndex, false);
23803 grid.view.focusRow(rowIndex);
23804 this.fireEvent("afterselectionchange", this);
23809 * Selects multiple rows.
23810 * @param {Array} rows Array of the indexes of the row to select
23811 * @param {Boolean} keepExisting (optional) True to keep existing selections
23813 selectRows : function(rows, keepExisting){
23815 this.clearSelections();
23817 for(var i = 0, len = rows.length; i < len; i++){
23818 this.selectRow(rows[i], true);
23823 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23824 * @param {Number} startRow The index of the first row in the range
23825 * @param {Number} endRow The index of the last row in the range
23826 * @param {Boolean} keepExisting (optional) True to retain existing selections
23828 selectRange : function(startRow, endRow, keepExisting){
23833 this.clearSelections();
23835 if(startRow <= endRow){
23836 for(var i = startRow; i <= endRow; i++){
23837 this.selectRow(i, true);
23840 for(var i = startRow; i >= endRow; i--){
23841 this.selectRow(i, true);
23847 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23848 * @param {Number} startRow The index of the first row in the range
23849 * @param {Number} endRow The index of the last row in the range
23851 deselectRange : function(startRow, endRow, preventViewNotify){
23855 for(var i = startRow; i <= endRow; i++){
23856 this.deselectRow(i, preventViewNotify);
23862 * @param {Number} row The index of the row to select
23863 * @param {Boolean} keepExisting (optional) True to keep existing selections
23865 selectRow : function(index, keepExisting, preventViewNotify)
23867 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23870 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23871 if(!keepExisting || this.singleSelect){
23872 this.clearSelections();
23875 var r = this.grid.store.getAt(index);
23876 //console.log('selectRow - record id :' + r.id);
23878 this.selections.add(r);
23879 this.last = this.lastActive = index;
23880 if(!preventViewNotify){
23881 var proxy = new Roo.Element(
23882 this.grid.getRowDom(index)
23884 proxy.addClass('bg-info info');
23886 this.fireEvent("rowselect", this, index, r);
23887 this.fireEvent("selectionchange", this);
23893 * @param {Number} row The index of the row to deselect
23895 deselectRow : function(index, preventViewNotify)
23900 if(this.last == index){
23903 if(this.lastActive == index){
23904 this.lastActive = false;
23907 var r = this.grid.store.getAt(index);
23912 this.selections.remove(r);
23913 //.console.log('deselectRow - record id :' + r.id);
23914 if(!preventViewNotify){
23916 var proxy = new Roo.Element(
23917 this.grid.getRowDom(index)
23919 proxy.removeClass('bg-info info');
23921 this.fireEvent("rowdeselect", this, index);
23922 this.fireEvent("selectionchange", this);
23926 restoreLast : function(){
23928 this.last = this._last;
23933 acceptsNav : function(row, col, cm){
23934 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23938 onEditorKey : function(field, e){
23939 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23944 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23946 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23948 }else if(k == e.ENTER && !e.ctrlKey){
23952 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23954 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23956 }else if(k == e.ESC){
23960 g.startEditing(newCell[0], newCell[1]);
23966 * Ext JS Library 1.1.1
23967 * Copyright(c) 2006-2007, Ext JS, LLC.
23969 * Originally Released Under LGPL - original licence link has changed is not relivant.
23972 * <script type="text/javascript">
23976 * @class Roo.bootstrap.PagingToolbar
23977 * @extends Roo.bootstrap.NavSimplebar
23978 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23980 * Create a new PagingToolbar
23981 * @param {Object} config The config object
23982 * @param {Roo.data.Store} store
23984 Roo.bootstrap.PagingToolbar = function(config)
23986 // old args format still supported... - xtype is prefered..
23987 // created from xtype...
23989 this.ds = config.dataSource;
23991 if (config.store && !this.ds) {
23992 this.store= Roo.factory(config.store, Roo.data);
23993 this.ds = this.store;
23994 this.ds.xmodule = this.xmodule || false;
23997 this.toolbarItems = [];
23998 if (config.items) {
23999 this.toolbarItems = config.items;
24002 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24007 this.bind(this.ds);
24010 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24014 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24016 * @cfg {Roo.data.Store} dataSource
24017 * The underlying data store providing the paged data
24020 * @cfg {String/HTMLElement/Element} container
24021 * container The id or element that will contain the toolbar
24024 * @cfg {Boolean} displayInfo
24025 * True to display the displayMsg (defaults to false)
24028 * @cfg {Number} pageSize
24029 * The number of records to display per page (defaults to 20)
24033 * @cfg {String} displayMsg
24034 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24036 displayMsg : 'Displaying {0} - {1} of {2}',
24038 * @cfg {String} emptyMsg
24039 * The message to display when no records are found (defaults to "No data to display")
24041 emptyMsg : 'No data to display',
24043 * Customizable piece of the default paging text (defaults to "Page")
24046 beforePageText : "Page",
24048 * Customizable piece of the default paging text (defaults to "of %0")
24051 afterPageText : "of {0}",
24053 * Customizable piece of the default paging text (defaults to "First Page")
24056 firstText : "First Page",
24058 * Customizable piece of the default paging text (defaults to "Previous Page")
24061 prevText : "Previous Page",
24063 * Customizable piece of the default paging text (defaults to "Next Page")
24066 nextText : "Next Page",
24068 * Customizable piece of the default paging text (defaults to "Last Page")
24071 lastText : "Last Page",
24073 * Customizable piece of the default paging text (defaults to "Refresh")
24076 refreshText : "Refresh",
24080 onRender : function(ct, position)
24082 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24083 this.navgroup.parentId = this.id;
24084 this.navgroup.onRender(this.el, null);
24085 // add the buttons to the navgroup
24087 if(this.displayInfo){
24088 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24089 this.displayEl = this.el.select('.x-paging-info', true).first();
24090 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24091 // this.displayEl = navel.el.select('span',true).first();
24097 Roo.each(_this.buttons, function(e){ // this might need to use render????
24098 Roo.factory(e).onRender(_this.el, null);
24102 Roo.each(_this.toolbarItems, function(e) {
24103 _this.navgroup.addItem(e);
24107 this.first = this.navgroup.addItem({
24108 tooltip: this.firstText,
24110 icon : 'fa fa-backward',
24112 preventDefault: true,
24113 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24116 this.prev = this.navgroup.addItem({
24117 tooltip: this.prevText,
24119 icon : 'fa fa-step-backward',
24121 preventDefault: true,
24122 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24124 //this.addSeparator();
24127 var field = this.navgroup.addItem( {
24129 cls : 'x-paging-position',
24131 html : this.beforePageText +
24132 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24133 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24136 this.field = field.el.select('input', true).first();
24137 this.field.on("keydown", this.onPagingKeydown, this);
24138 this.field.on("focus", function(){this.dom.select();});
24141 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24142 //this.field.setHeight(18);
24143 //this.addSeparator();
24144 this.next = this.navgroup.addItem({
24145 tooltip: this.nextText,
24147 html : ' <i class="fa fa-step-forward">',
24149 preventDefault: true,
24150 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24152 this.last = this.navgroup.addItem({
24153 tooltip: this.lastText,
24154 icon : 'fa fa-forward',
24157 preventDefault: true,
24158 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24160 //this.addSeparator();
24161 this.loading = this.navgroup.addItem({
24162 tooltip: this.refreshText,
24163 icon: 'fa fa-refresh',
24164 preventDefault: true,
24165 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24171 updateInfo : function(){
24172 if(this.displayEl){
24173 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24174 var msg = count == 0 ?
24178 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24180 this.displayEl.update(msg);
24185 onLoad : function(ds, r, o){
24186 this.cursor = o.params ? o.params.start : 0;
24187 var d = this.getPageData(),
24191 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24192 this.field.dom.value = ap;
24193 this.first.setDisabled(ap == 1);
24194 this.prev.setDisabled(ap == 1);
24195 this.next.setDisabled(ap == ps);
24196 this.last.setDisabled(ap == ps);
24197 this.loading.enable();
24202 getPageData : function(){
24203 var total = this.ds.getTotalCount();
24206 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24207 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24212 onLoadError : function(){
24213 this.loading.enable();
24217 onPagingKeydown : function(e){
24218 var k = e.getKey();
24219 var d = this.getPageData();
24221 var v = this.field.dom.value, pageNum;
24222 if(!v || isNaN(pageNum = parseInt(v, 10))){
24223 this.field.dom.value = d.activePage;
24226 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24227 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24230 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))
24232 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24233 this.field.dom.value = pageNum;
24234 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24237 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24239 var v = this.field.dom.value, pageNum;
24240 var increment = (e.shiftKey) ? 10 : 1;
24241 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24244 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24245 this.field.dom.value = d.activePage;
24248 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24250 this.field.dom.value = parseInt(v, 10) + increment;
24251 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24252 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24259 beforeLoad : function(){
24261 this.loading.disable();
24266 onClick : function(which){
24275 ds.load({params:{start: 0, limit: this.pageSize}});
24278 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24281 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24284 var total = ds.getTotalCount();
24285 var extra = total % this.pageSize;
24286 var lastStart = extra ? (total - extra) : total-this.pageSize;
24287 ds.load({params:{start: lastStart, limit: this.pageSize}});
24290 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24296 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24297 * @param {Roo.data.Store} store The data store to unbind
24299 unbind : function(ds){
24300 ds.un("beforeload", this.beforeLoad, this);
24301 ds.un("load", this.onLoad, this);
24302 ds.un("loadexception", this.onLoadError, this);
24303 ds.un("remove", this.updateInfo, this);
24304 ds.un("add", this.updateInfo, this);
24305 this.ds = undefined;
24309 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24310 * @param {Roo.data.Store} store The data store to bind
24312 bind : function(ds){
24313 ds.on("beforeload", this.beforeLoad, this);
24314 ds.on("load", this.onLoad, this);
24315 ds.on("loadexception", this.onLoadError, this);
24316 ds.on("remove", this.updateInfo, this);
24317 ds.on("add", this.updateInfo, this);
24328 * @class Roo.bootstrap.MessageBar
24329 * @extends Roo.bootstrap.Component
24330 * Bootstrap MessageBar class
24331 * @cfg {String} html contents of the MessageBar
24332 * @cfg {String} weight (info | success | warning | danger) default info
24333 * @cfg {String} beforeClass insert the bar before the given class
24334 * @cfg {Boolean} closable (true | false) default false
24335 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24338 * Create a new Element
24339 * @param {Object} config The config object
24342 Roo.bootstrap.MessageBar = function(config){
24343 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24346 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24352 beforeClass: 'bootstrap-sticky-wrap',
24354 getAutoCreate : function(){
24358 cls: 'alert alert-dismissable alert-' + this.weight,
24363 html: this.html || ''
24369 cfg.cls += ' alert-messages-fixed';
24383 onRender : function(ct, position)
24385 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24388 var cfg = Roo.apply({}, this.getAutoCreate());
24392 cfg.cls += ' ' + this.cls;
24395 cfg.style = this.style;
24397 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24399 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24402 this.el.select('>button.close').on('click', this.hide, this);
24408 if (!this.rendered) {
24414 this.fireEvent('show', this);
24420 if (!this.rendered) {
24426 this.fireEvent('hide', this);
24429 update : function()
24431 // var e = this.el.dom.firstChild;
24433 // if(this.closable){
24434 // e = e.nextSibling;
24437 // e.data = this.html || '';
24439 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24455 * @class Roo.bootstrap.Graph
24456 * @extends Roo.bootstrap.Component
24457 * Bootstrap Graph class
24461 @cfg {String} graphtype bar | vbar | pie
24462 @cfg {number} g_x coodinator | centre x (pie)
24463 @cfg {number} g_y coodinator | centre y (pie)
24464 @cfg {number} g_r radius (pie)
24465 @cfg {number} g_height height of the chart (respected by all elements in the set)
24466 @cfg {number} g_width width of the chart (respected by all elements in the set)
24467 @cfg {Object} title The title of the chart
24470 -opts (object) options for the chart
24472 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24473 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24475 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.
24476 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24478 o stretch (boolean)
24480 -opts (object) options for the pie
24483 o startAngle (number)
24484 o endAngle (number)
24488 * Create a new Input
24489 * @param {Object} config The config object
24492 Roo.bootstrap.Graph = function(config){
24493 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24499 * The img click event for the img.
24500 * @param {Roo.EventObject} e
24506 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24517 //g_colors: this.colors,
24524 getAutoCreate : function(){
24535 onRender : function(ct,position){
24538 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24540 if (typeof(Raphael) == 'undefined') {
24541 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24545 this.raphael = Raphael(this.el.dom);
24547 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24548 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24549 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24550 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24552 r.text(160, 10, "Single Series Chart").attr(txtattr);
24553 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24554 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24555 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24557 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24558 r.barchart(330, 10, 300, 220, data1);
24559 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24560 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24563 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24564 // r.barchart(30, 30, 560, 250, xdata, {
24565 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24566 // axis : "0 0 1 1",
24567 // axisxlabels : xdata
24568 // //yvalues : cols,
24571 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24573 // this.load(null,xdata,{
24574 // axis : "0 0 1 1",
24575 // axisxlabels : xdata
24580 load : function(graphtype,xdata,opts)
24582 this.raphael.clear();
24584 graphtype = this.graphtype;
24589 var r = this.raphael,
24590 fin = function () {
24591 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24593 fout = function () {
24594 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24596 pfin = function() {
24597 this.sector.stop();
24598 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24601 this.label[0].stop();
24602 this.label[0].attr({ r: 7.5 });
24603 this.label[1].attr({ "font-weight": 800 });
24606 pfout = function() {
24607 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24610 this.label[0].animate({ r: 5 }, 500, "bounce");
24611 this.label[1].attr({ "font-weight": 400 });
24617 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24620 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24623 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24624 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24626 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24633 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24638 setTitle: function(o)
24643 initEvents: function() {
24646 this.el.on('click', this.onClick, this);
24650 onClick : function(e)
24652 Roo.log('img onclick');
24653 this.fireEvent('click', this, e);
24665 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24668 * @class Roo.bootstrap.dash.NumberBox
24669 * @extends Roo.bootstrap.Component
24670 * Bootstrap NumberBox class
24671 * @cfg {String} headline Box headline
24672 * @cfg {String} content Box content
24673 * @cfg {String} icon Box icon
24674 * @cfg {String} footer Footer text
24675 * @cfg {String} fhref Footer href
24678 * Create a new NumberBox
24679 * @param {Object} config The config object
24683 Roo.bootstrap.dash.NumberBox = function(config){
24684 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24688 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24697 getAutoCreate : function(){
24701 cls : 'small-box ',
24709 cls : 'roo-headline',
24710 html : this.headline
24714 cls : 'roo-content',
24715 html : this.content
24729 cls : 'ion ' + this.icon
24738 cls : 'small-box-footer',
24739 href : this.fhref || '#',
24743 cfg.cn.push(footer);
24750 onRender : function(ct,position){
24751 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24758 setHeadline: function (value)
24760 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24763 setFooter: function (value, href)
24765 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24768 this.el.select('a.small-box-footer',true).first().attr('href', href);
24773 setContent: function (value)
24775 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24778 initEvents: function()
24792 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24795 * @class Roo.bootstrap.dash.TabBox
24796 * @extends Roo.bootstrap.Component
24797 * Bootstrap TabBox class
24798 * @cfg {String} title Title of the TabBox
24799 * @cfg {String} icon Icon of the TabBox
24800 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24801 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24804 * Create a new TabBox
24805 * @param {Object} config The config object
24809 Roo.bootstrap.dash.TabBox = function(config){
24810 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24815 * When a pane is added
24816 * @param {Roo.bootstrap.dash.TabPane} pane
24820 * @event activatepane
24821 * When a pane is activated
24822 * @param {Roo.bootstrap.dash.TabPane} pane
24824 "activatepane" : true
24832 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24837 tabScrollable : false,
24839 getChildContainer : function()
24841 return this.el.select('.tab-content', true).first();
24844 getAutoCreate : function(){
24848 cls: 'pull-left header',
24856 cls: 'fa ' + this.icon
24862 cls: 'nav nav-tabs pull-right',
24868 if(this.tabScrollable){
24875 cls: 'nav nav-tabs pull-right',
24886 cls: 'nav-tabs-custom',
24891 cls: 'tab-content no-padding',
24899 initEvents : function()
24901 //Roo.log('add add pane handler');
24902 this.on('addpane', this.onAddPane, this);
24905 * Updates the box title
24906 * @param {String} html to set the title to.
24908 setTitle : function(value)
24910 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24912 onAddPane : function(pane)
24914 this.panes.push(pane);
24915 //Roo.log('addpane');
24917 // tabs are rendere left to right..
24918 if(!this.showtabs){
24922 var ctr = this.el.select('.nav-tabs', true).first();
24925 var existing = ctr.select('.nav-tab',true);
24926 var qty = existing.getCount();;
24929 var tab = ctr.createChild({
24931 cls : 'nav-tab' + (qty ? '' : ' active'),
24939 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24942 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24944 pane.el.addClass('active');
24949 onTabClick : function(ev,un,ob,pane)
24951 //Roo.log('tab - prev default');
24952 ev.preventDefault();
24955 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24956 pane.tab.addClass('active');
24957 //Roo.log(pane.title);
24958 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24959 // technically we should have a deactivate event.. but maybe add later.
24960 // and it should not de-activate the selected tab...
24961 this.fireEvent('activatepane', pane);
24962 pane.el.addClass('active');
24963 pane.fireEvent('activate');
24968 getActivePane : function()
24971 Roo.each(this.panes, function(p) {
24972 if(p.el.hasClass('active')){
24993 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24995 * @class Roo.bootstrap.TabPane
24996 * @extends Roo.bootstrap.Component
24997 * Bootstrap TabPane class
24998 * @cfg {Boolean} active (false | true) Default false
24999 * @cfg {String} title title of panel
25003 * Create a new TabPane
25004 * @param {Object} config The config object
25007 Roo.bootstrap.dash.TabPane = function(config){
25008 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25014 * When a pane is activated
25015 * @param {Roo.bootstrap.dash.TabPane} pane
25022 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25027 // the tabBox that this is attached to.
25030 getAutoCreate : function()
25038 cfg.cls += ' active';
25043 initEvents : function()
25045 //Roo.log('trigger add pane handler');
25046 this.parent().fireEvent('addpane', this)
25050 * Updates the tab title
25051 * @param {String} html to set the title to.
25053 setTitle: function(str)
25059 this.tab.select('a', true).first().dom.innerHTML = str;
25076 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25079 * @class Roo.bootstrap.menu.Menu
25080 * @extends Roo.bootstrap.Component
25081 * Bootstrap Menu class - container for Menu
25082 * @cfg {String} html Text of the menu
25083 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25084 * @cfg {String} icon Font awesome icon
25085 * @cfg {String} pos Menu align to (top | bottom) default bottom
25089 * Create a new Menu
25090 * @param {Object} config The config object
25094 Roo.bootstrap.menu.Menu = function(config){
25095 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25099 * @event beforeshow
25100 * Fires before this menu is displayed
25101 * @param {Roo.bootstrap.menu.Menu} this
25105 * @event beforehide
25106 * Fires before this menu is hidden
25107 * @param {Roo.bootstrap.menu.Menu} this
25112 * Fires after this menu is displayed
25113 * @param {Roo.bootstrap.menu.Menu} this
25118 * Fires after this menu is hidden
25119 * @param {Roo.bootstrap.menu.Menu} this
25124 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25125 * @param {Roo.bootstrap.menu.Menu} this
25126 * @param {Roo.EventObject} e
25133 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25137 weight : 'default',
25142 getChildContainer : function() {
25143 if(this.isSubMenu){
25147 return this.el.select('ul.dropdown-menu', true).first();
25150 getAutoCreate : function()
25155 cls : 'roo-menu-text',
25163 cls : 'fa ' + this.icon
25174 cls : 'dropdown-button btn btn-' + this.weight,
25179 cls : 'dropdown-toggle btn btn-' + this.weight,
25189 cls : 'dropdown-menu'
25195 if(this.pos == 'top'){
25196 cfg.cls += ' dropup';
25199 if(this.isSubMenu){
25202 cls : 'dropdown-menu'
25209 onRender : function(ct, position)
25211 this.isSubMenu = ct.hasClass('dropdown-submenu');
25213 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25216 initEvents : function()
25218 if(this.isSubMenu){
25222 this.hidden = true;
25224 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25225 this.triggerEl.on('click', this.onTriggerPress, this);
25227 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25228 this.buttonEl.on('click', this.onClick, this);
25234 if(this.isSubMenu){
25238 return this.el.select('ul.dropdown-menu', true).first();
25241 onClick : function(e)
25243 this.fireEvent("click", this, e);
25246 onTriggerPress : function(e)
25248 if (this.isVisible()) {
25255 isVisible : function(){
25256 return !this.hidden;
25261 this.fireEvent("beforeshow", this);
25263 this.hidden = false;
25264 this.el.addClass('open');
25266 Roo.get(document).on("mouseup", this.onMouseUp, this);
25268 this.fireEvent("show", this);
25275 this.fireEvent("beforehide", this);
25277 this.hidden = true;
25278 this.el.removeClass('open');
25280 Roo.get(document).un("mouseup", this.onMouseUp);
25282 this.fireEvent("hide", this);
25285 onMouseUp : function()
25299 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25302 * @class Roo.bootstrap.menu.Item
25303 * @extends Roo.bootstrap.Component
25304 * Bootstrap MenuItem class
25305 * @cfg {Boolean} submenu (true | false) default false
25306 * @cfg {String} html text of the item
25307 * @cfg {String} href the link
25308 * @cfg {Boolean} disable (true | false) default false
25309 * @cfg {Boolean} preventDefault (true | false) default true
25310 * @cfg {String} icon Font awesome icon
25311 * @cfg {String} pos Submenu align to (left | right) default right
25315 * Create a new Item
25316 * @param {Object} config The config object
25320 Roo.bootstrap.menu.Item = function(config){
25321 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25325 * Fires when the mouse is hovering over this menu
25326 * @param {Roo.bootstrap.menu.Item} this
25327 * @param {Roo.EventObject} e
25332 * Fires when the mouse exits this menu
25333 * @param {Roo.bootstrap.menu.Item} this
25334 * @param {Roo.EventObject} e
25340 * The raw click event for the entire grid.
25341 * @param {Roo.EventObject} e
25347 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25352 preventDefault: true,
25357 getAutoCreate : function()
25362 cls : 'roo-menu-item-text',
25370 cls : 'fa ' + this.icon
25379 href : this.href || '#',
25386 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25390 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25392 if(this.pos == 'left'){
25393 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25400 initEvents : function()
25402 this.el.on('mouseover', this.onMouseOver, this);
25403 this.el.on('mouseout', this.onMouseOut, this);
25405 this.el.select('a', true).first().on('click', this.onClick, this);
25409 onClick : function(e)
25411 if(this.preventDefault){
25412 e.preventDefault();
25415 this.fireEvent("click", this, e);
25418 onMouseOver : function(e)
25420 if(this.submenu && this.pos == 'left'){
25421 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25424 this.fireEvent("mouseover", this, e);
25427 onMouseOut : function(e)
25429 this.fireEvent("mouseout", this, e);
25441 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25444 * @class Roo.bootstrap.menu.Separator
25445 * @extends Roo.bootstrap.Component
25446 * Bootstrap Separator class
25449 * Create a new Separator
25450 * @param {Object} config The config object
25454 Roo.bootstrap.menu.Separator = function(config){
25455 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25458 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25460 getAutoCreate : function(){
25481 * @class Roo.bootstrap.Tooltip
25482 * Bootstrap Tooltip class
25483 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25484 * to determine which dom element triggers the tooltip.
25486 * It needs to add support for additional attributes like tooltip-position
25489 * Create a new Toolti
25490 * @param {Object} config The config object
25493 Roo.bootstrap.Tooltip = function(config){
25494 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25496 this.alignment = Roo.bootstrap.Tooltip.alignment;
25498 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25499 this.alignment = config.alignment;
25504 Roo.apply(Roo.bootstrap.Tooltip, {
25506 * @function init initialize tooltip monitoring.
25510 currentTip : false,
25511 currentRegion : false,
25517 Roo.get(document).on('mouseover', this.enter ,this);
25518 Roo.get(document).on('mouseout', this.leave, this);
25521 this.currentTip = new Roo.bootstrap.Tooltip();
25524 enter : function(ev)
25526 var dom = ev.getTarget();
25528 //Roo.log(['enter',dom]);
25529 var el = Roo.fly(dom);
25530 if (this.currentEl) {
25532 //Roo.log(this.currentEl);
25533 //Roo.log(this.currentEl.contains(dom));
25534 if (this.currentEl == el) {
25537 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25543 if (this.currentTip.el) {
25544 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25548 if(!el || el.dom == document){
25554 // you can not look for children, as if el is the body.. then everythign is the child..
25555 if (!el.attr('tooltip')) { //
25556 if (!el.select("[tooltip]").elements.length) {
25559 // is the mouse over this child...?
25560 bindEl = el.select("[tooltip]").first();
25561 var xy = ev.getXY();
25562 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25563 //Roo.log("not in region.");
25566 //Roo.log("child element over..");
25569 this.currentEl = bindEl;
25570 this.currentTip.bind(bindEl);
25571 this.currentRegion = Roo.lib.Region.getRegion(dom);
25572 this.currentTip.enter();
25575 leave : function(ev)
25577 var dom = ev.getTarget();
25578 //Roo.log(['leave',dom]);
25579 if (!this.currentEl) {
25584 if (dom != this.currentEl.dom) {
25587 var xy = ev.getXY();
25588 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25591 // only activate leave if mouse cursor is outside... bounding box..
25596 if (this.currentTip) {
25597 this.currentTip.leave();
25599 //Roo.log('clear currentEl');
25600 this.currentEl = false;
25605 'left' : ['r-l', [-2,0], 'right'],
25606 'right' : ['l-r', [2,0], 'left'],
25607 'bottom' : ['t-b', [0,2], 'top'],
25608 'top' : [ 'b-t', [0,-2], 'bottom']
25614 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25619 delay : null, // can be { show : 300 , hide: 500}
25623 hoverState : null, //???
25625 placement : 'bottom',
25629 getAutoCreate : function(){
25636 cls : 'tooltip-arrow'
25639 cls : 'tooltip-inner'
25646 bind : function(el)
25652 enter : function () {
25654 if (this.timeout != null) {
25655 clearTimeout(this.timeout);
25658 this.hoverState = 'in';
25659 //Roo.log("enter - show");
25660 if (!this.delay || !this.delay.show) {
25665 this.timeout = setTimeout(function () {
25666 if (_t.hoverState == 'in') {
25669 }, this.delay.show);
25673 clearTimeout(this.timeout);
25675 this.hoverState = 'out';
25676 if (!this.delay || !this.delay.hide) {
25682 this.timeout = setTimeout(function () {
25683 //Roo.log("leave - timeout");
25685 if (_t.hoverState == 'out') {
25687 Roo.bootstrap.Tooltip.currentEl = false;
25692 show : function (msg)
25695 this.render(document.body);
25698 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25700 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25702 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25704 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25706 var placement = typeof this.placement == 'function' ?
25707 this.placement.call(this, this.el, on_el) :
25710 var autoToken = /\s?auto?\s?/i;
25711 var autoPlace = autoToken.test(placement);
25713 placement = placement.replace(autoToken, '') || 'top';
25717 //this.el.setXY([0,0]);
25719 //this.el.dom.style.display='block';
25721 //this.el.appendTo(on_el);
25723 var p = this.getPosition();
25724 var box = this.el.getBox();
25730 var align = this.alignment[placement];
25732 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25734 if(placement == 'top' || placement == 'bottom'){
25736 placement = 'right';
25739 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25740 placement = 'left';
25743 var scroll = Roo.select('body', true).first().getScroll();
25745 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25751 this.el.alignTo(this.bindEl, align[0],align[1]);
25752 //var arrow = this.el.select('.arrow',true).first();
25753 //arrow.set(align[2],
25755 this.el.addClass(placement);
25757 this.el.addClass('in fade');
25759 this.hoverState = null;
25761 if (this.el.hasClass('fade')) {
25772 //this.el.setXY([0,0]);
25773 this.el.removeClass('in');
25789 * @class Roo.bootstrap.LocationPicker
25790 * @extends Roo.bootstrap.Component
25791 * Bootstrap LocationPicker class
25792 * @cfg {Number} latitude Position when init default 0
25793 * @cfg {Number} longitude Position when init default 0
25794 * @cfg {Number} zoom default 15
25795 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25796 * @cfg {Boolean} mapTypeControl default false
25797 * @cfg {Boolean} disableDoubleClickZoom default false
25798 * @cfg {Boolean} scrollwheel default true
25799 * @cfg {Boolean} streetViewControl default false
25800 * @cfg {Number} radius default 0
25801 * @cfg {String} locationName
25802 * @cfg {Boolean} draggable default true
25803 * @cfg {Boolean} enableAutocomplete default false
25804 * @cfg {Boolean} enableReverseGeocode default true
25805 * @cfg {String} markerTitle
25808 * Create a new LocationPicker
25809 * @param {Object} config The config object
25813 Roo.bootstrap.LocationPicker = function(config){
25815 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25820 * Fires when the picker initialized.
25821 * @param {Roo.bootstrap.LocationPicker} this
25822 * @param {Google Location} location
25826 * @event positionchanged
25827 * Fires when the picker position changed.
25828 * @param {Roo.bootstrap.LocationPicker} this
25829 * @param {Google Location} location
25831 positionchanged : true,
25834 * Fires when the map resize.
25835 * @param {Roo.bootstrap.LocationPicker} this
25840 * Fires when the map show.
25841 * @param {Roo.bootstrap.LocationPicker} this
25846 * Fires when the map hide.
25847 * @param {Roo.bootstrap.LocationPicker} this
25852 * Fires when click the map.
25853 * @param {Roo.bootstrap.LocationPicker} this
25854 * @param {Map event} e
25858 * @event mapRightClick
25859 * Fires when right click the map.
25860 * @param {Roo.bootstrap.LocationPicker} this
25861 * @param {Map event} e
25863 mapRightClick : true,
25865 * @event markerClick
25866 * Fires when click the marker.
25867 * @param {Roo.bootstrap.LocationPicker} this
25868 * @param {Map event} e
25870 markerClick : true,
25872 * @event markerRightClick
25873 * Fires when right click the marker.
25874 * @param {Roo.bootstrap.LocationPicker} this
25875 * @param {Map event} e
25877 markerRightClick : true,
25879 * @event OverlayViewDraw
25880 * Fires when OverlayView Draw
25881 * @param {Roo.bootstrap.LocationPicker} this
25883 OverlayViewDraw : true,
25885 * @event OverlayViewOnAdd
25886 * Fires when OverlayView Draw
25887 * @param {Roo.bootstrap.LocationPicker} this
25889 OverlayViewOnAdd : true,
25891 * @event OverlayViewOnRemove
25892 * Fires when OverlayView Draw
25893 * @param {Roo.bootstrap.LocationPicker} this
25895 OverlayViewOnRemove : true,
25897 * @event OverlayViewShow
25898 * Fires when OverlayView Draw
25899 * @param {Roo.bootstrap.LocationPicker} this
25900 * @param {Pixel} cpx
25902 OverlayViewShow : true,
25904 * @event OverlayViewHide
25905 * Fires when OverlayView Draw
25906 * @param {Roo.bootstrap.LocationPicker} this
25908 OverlayViewHide : true,
25910 * @event loadexception
25911 * Fires when load google lib failed.
25912 * @param {Roo.bootstrap.LocationPicker} this
25914 loadexception : true
25919 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25921 gMapContext: false,
25927 mapTypeControl: false,
25928 disableDoubleClickZoom: false,
25930 streetViewControl: false,
25934 enableAutocomplete: false,
25935 enableReverseGeocode: true,
25938 getAutoCreate: function()
25943 cls: 'roo-location-picker'
25949 initEvents: function(ct, position)
25951 if(!this.el.getWidth() || this.isApplied()){
25955 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25960 initial: function()
25962 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25963 this.fireEvent('loadexception', this);
25967 if(!this.mapTypeId){
25968 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25971 this.gMapContext = this.GMapContext();
25973 this.initOverlayView();
25975 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25979 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25980 _this.setPosition(_this.gMapContext.marker.position);
25983 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25984 _this.fireEvent('mapClick', this, event);
25988 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25989 _this.fireEvent('mapRightClick', this, event);
25993 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25994 _this.fireEvent('markerClick', this, event);
25998 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25999 _this.fireEvent('markerRightClick', this, event);
26003 this.setPosition(this.gMapContext.location);
26005 this.fireEvent('initial', this, this.gMapContext.location);
26008 initOverlayView: function()
26012 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26016 _this.fireEvent('OverlayViewDraw', _this);
26021 _this.fireEvent('OverlayViewOnAdd', _this);
26024 onRemove: function()
26026 _this.fireEvent('OverlayViewOnRemove', _this);
26029 show: function(cpx)
26031 _this.fireEvent('OverlayViewShow', _this, cpx);
26036 _this.fireEvent('OverlayViewHide', _this);
26042 fromLatLngToContainerPixel: function(event)
26044 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26047 isApplied: function()
26049 return this.getGmapContext() == false ? false : true;
26052 getGmapContext: function()
26054 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26057 GMapContext: function()
26059 var position = new google.maps.LatLng(this.latitude, this.longitude);
26061 var _map = new google.maps.Map(this.el.dom, {
26064 mapTypeId: this.mapTypeId,
26065 mapTypeControl: this.mapTypeControl,
26066 disableDoubleClickZoom: this.disableDoubleClickZoom,
26067 scrollwheel: this.scrollwheel,
26068 streetViewControl: this.streetViewControl,
26069 locationName: this.locationName,
26070 draggable: this.draggable,
26071 enableAutocomplete: this.enableAutocomplete,
26072 enableReverseGeocode: this.enableReverseGeocode
26075 var _marker = new google.maps.Marker({
26076 position: position,
26078 title: this.markerTitle,
26079 draggable: this.draggable
26086 location: position,
26087 radius: this.radius,
26088 locationName: this.locationName,
26089 addressComponents: {
26090 formatted_address: null,
26091 addressLine1: null,
26092 addressLine2: null,
26094 streetNumber: null,
26098 stateOrProvince: null
26101 domContainer: this.el.dom,
26102 geodecoder: new google.maps.Geocoder()
26106 drawCircle: function(center, radius, options)
26108 if (this.gMapContext.circle != null) {
26109 this.gMapContext.circle.setMap(null);
26113 options = Roo.apply({}, options, {
26114 strokeColor: "#0000FF",
26115 strokeOpacity: .35,
26117 fillColor: "#0000FF",
26121 options.map = this.gMapContext.map;
26122 options.radius = radius;
26123 options.center = center;
26124 this.gMapContext.circle = new google.maps.Circle(options);
26125 return this.gMapContext.circle;
26131 setPosition: function(location)
26133 this.gMapContext.location = location;
26134 this.gMapContext.marker.setPosition(location);
26135 this.gMapContext.map.panTo(location);
26136 this.drawCircle(location, this.gMapContext.radius, {});
26140 if (this.gMapContext.settings.enableReverseGeocode) {
26141 this.gMapContext.geodecoder.geocode({
26142 latLng: this.gMapContext.location
26143 }, function(results, status) {
26145 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26146 _this.gMapContext.locationName = results[0].formatted_address;
26147 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26149 _this.fireEvent('positionchanged', this, location);
26156 this.fireEvent('positionchanged', this, location);
26161 google.maps.event.trigger(this.gMapContext.map, "resize");
26163 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26165 this.fireEvent('resize', this);
26168 setPositionByLatLng: function(latitude, longitude)
26170 this.setPosition(new google.maps.LatLng(latitude, longitude));
26173 getCurrentPosition: function()
26176 latitude: this.gMapContext.location.lat(),
26177 longitude: this.gMapContext.location.lng()
26181 getAddressName: function()
26183 return this.gMapContext.locationName;
26186 getAddressComponents: function()
26188 return this.gMapContext.addressComponents;
26191 address_component_from_google_geocode: function(address_components)
26195 for (var i = 0; i < address_components.length; i++) {
26196 var component = address_components[i];
26197 if (component.types.indexOf("postal_code") >= 0) {
26198 result.postalCode = component.short_name;
26199 } else if (component.types.indexOf("street_number") >= 0) {
26200 result.streetNumber = component.short_name;
26201 } else if (component.types.indexOf("route") >= 0) {
26202 result.streetName = component.short_name;
26203 } else if (component.types.indexOf("neighborhood") >= 0) {
26204 result.city = component.short_name;
26205 } else if (component.types.indexOf("locality") >= 0) {
26206 result.city = component.short_name;
26207 } else if (component.types.indexOf("sublocality") >= 0) {
26208 result.district = component.short_name;
26209 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26210 result.stateOrProvince = component.short_name;
26211 } else if (component.types.indexOf("country") >= 0) {
26212 result.country = component.short_name;
26216 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26217 result.addressLine2 = "";
26221 setZoomLevel: function(zoom)
26223 this.gMapContext.map.setZoom(zoom);
26236 this.fireEvent('show', this);
26247 this.fireEvent('hide', this);
26252 Roo.apply(Roo.bootstrap.LocationPicker, {
26254 OverlayView : function(map, options)
26256 options = options || {};
26270 * @class Roo.bootstrap.Alert
26271 * @extends Roo.bootstrap.Component
26272 * Bootstrap Alert class
26273 * @cfg {String} title The title of alert
26274 * @cfg {String} html The content of alert
26275 * @cfg {String} weight ( success | info | warning | danger )
26276 * @cfg {String} faicon font-awesomeicon
26279 * Create a new alert
26280 * @param {Object} config The config object
26284 Roo.bootstrap.Alert = function(config){
26285 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26289 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26296 getAutoCreate : function()
26305 cls : 'roo-alert-icon'
26310 cls : 'roo-alert-title',
26315 cls : 'roo-alert-text',
26322 cfg.cn[0].cls += ' fa ' + this.faicon;
26326 cfg.cls += ' alert-' + this.weight;
26332 initEvents: function()
26334 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26337 setTitle : function(str)
26339 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26342 setText : function(str)
26344 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26347 setWeight : function(weight)
26350 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26353 this.weight = weight;
26355 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26358 setIcon : function(icon)
26361 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26364 this.faicon = icon;
26366 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26387 * @class Roo.bootstrap.UploadCropbox
26388 * @extends Roo.bootstrap.Component
26389 * Bootstrap UploadCropbox class
26390 * @cfg {String} emptyText show when image has been loaded
26391 * @cfg {String} rotateNotify show when image too small to rotate
26392 * @cfg {Number} errorTimeout default 3000
26393 * @cfg {Number} minWidth default 300
26394 * @cfg {Number} minHeight default 300
26395 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26396 * @cfg {Boolean} isDocument (true|false) default false
26397 * @cfg {String} url action url
26398 * @cfg {String} paramName default 'imageUpload'
26399 * @cfg {String} method default POST
26400 * @cfg {Boolean} loadMask (true|false) default true
26401 * @cfg {Boolean} loadingText default 'Loading...'
26404 * Create a new UploadCropbox
26405 * @param {Object} config The config object
26408 Roo.bootstrap.UploadCropbox = function(config){
26409 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26413 * @event beforeselectfile
26414 * Fire before select file
26415 * @param {Roo.bootstrap.UploadCropbox} this
26417 "beforeselectfile" : true,
26420 * Fire after initEvent
26421 * @param {Roo.bootstrap.UploadCropbox} this
26426 * Fire after initEvent
26427 * @param {Roo.bootstrap.UploadCropbox} this
26428 * @param {String} data
26433 * Fire when preparing the file data
26434 * @param {Roo.bootstrap.UploadCropbox} this
26435 * @param {Object} file
26440 * Fire when get exception
26441 * @param {Roo.bootstrap.UploadCropbox} this
26442 * @param {XMLHttpRequest} xhr
26444 "exception" : true,
26446 * @event beforeloadcanvas
26447 * Fire before load the canvas
26448 * @param {Roo.bootstrap.UploadCropbox} this
26449 * @param {String} src
26451 "beforeloadcanvas" : true,
26454 * Fire when trash image
26455 * @param {Roo.bootstrap.UploadCropbox} this
26460 * Fire when download the image
26461 * @param {Roo.bootstrap.UploadCropbox} this
26465 * @event footerbuttonclick
26466 * Fire when footerbuttonclick
26467 * @param {Roo.bootstrap.UploadCropbox} this
26468 * @param {String} type
26470 "footerbuttonclick" : true,
26474 * @param {Roo.bootstrap.UploadCropbox} this
26479 * Fire when rotate the image
26480 * @param {Roo.bootstrap.UploadCropbox} this
26481 * @param {String} pos
26486 * Fire when inspect the file
26487 * @param {Roo.bootstrap.UploadCropbox} this
26488 * @param {Object} file
26493 * Fire when xhr upload the file
26494 * @param {Roo.bootstrap.UploadCropbox} this
26495 * @param {Object} data
26500 * Fire when arrange the file data
26501 * @param {Roo.bootstrap.UploadCropbox} this
26502 * @param {Object} formData
26507 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26510 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26512 emptyText : 'Click to upload image',
26513 rotateNotify : 'Image is too small to rotate',
26514 errorTimeout : 3000,
26528 cropType : 'image/jpeg',
26530 canvasLoaded : false,
26531 isDocument : false,
26533 paramName : 'imageUpload',
26535 loadingText : 'Loading...',
26538 getAutoCreate : function()
26542 cls : 'roo-upload-cropbox',
26546 cls : 'roo-upload-cropbox-selector',
26551 cls : 'roo-upload-cropbox-body',
26552 style : 'cursor:pointer',
26556 cls : 'roo-upload-cropbox-preview'
26560 cls : 'roo-upload-cropbox-thumb'
26564 cls : 'roo-upload-cropbox-empty-notify',
26565 html : this.emptyText
26569 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26570 html : this.rotateNotify
26576 cls : 'roo-upload-cropbox-footer',
26579 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26589 onRender : function(ct, position)
26591 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26593 if (this.buttons.length) {
26595 Roo.each(this.buttons, function(bb) {
26597 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26599 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26605 this.maskEl = this.el;
26609 initEvents : function()
26611 this.urlAPI = (window.createObjectURL && window) ||
26612 (window.URL && URL.revokeObjectURL && URL) ||
26613 (window.webkitURL && webkitURL);
26615 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26616 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26618 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26619 this.selectorEl.hide();
26621 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26622 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26624 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26625 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26626 this.thumbEl.hide();
26628 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26629 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26631 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26632 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26633 this.errorEl.hide();
26635 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26636 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26637 this.footerEl.hide();
26639 this.setThumbBoxSize();
26645 this.fireEvent('initial', this);
26652 window.addEventListener("resize", function() { _this.resize(); } );
26654 this.bodyEl.on('click', this.beforeSelectFile, this);
26657 this.bodyEl.on('touchstart', this.onTouchStart, this);
26658 this.bodyEl.on('touchmove', this.onTouchMove, this);
26659 this.bodyEl.on('touchend', this.onTouchEnd, this);
26663 this.bodyEl.on('mousedown', this.onMouseDown, this);
26664 this.bodyEl.on('mousemove', this.onMouseMove, this);
26665 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26666 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26667 Roo.get(document).on('mouseup', this.onMouseUp, this);
26670 this.selectorEl.on('change', this.onFileSelected, this);
26676 this.baseScale = 1;
26678 this.baseRotate = 1;
26679 this.dragable = false;
26680 this.pinching = false;
26683 this.cropData = false;
26684 this.notifyEl.dom.innerHTML = this.emptyText;
26686 this.selectorEl.dom.value = '';
26690 resize : function()
26692 if(this.fireEvent('resize', this) != false){
26693 this.setThumbBoxPosition();
26694 this.setCanvasPosition();
26698 onFooterButtonClick : function(e, el, o, type)
26701 case 'rotate-left' :
26702 this.onRotateLeft(e);
26704 case 'rotate-right' :
26705 this.onRotateRight(e);
26708 this.beforeSelectFile(e);
26723 this.fireEvent('footerbuttonclick', this, type);
26726 beforeSelectFile : function(e)
26728 e.preventDefault();
26730 if(this.fireEvent('beforeselectfile', this) != false){
26731 this.selectorEl.dom.click();
26735 onFileSelected : function(e)
26737 e.preventDefault();
26739 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26743 var file = this.selectorEl.dom.files[0];
26745 if(this.fireEvent('inspect', this, file) != false){
26746 this.prepare(file);
26751 trash : function(e)
26753 this.fireEvent('trash', this);
26756 download : function(e)
26758 this.fireEvent('download', this);
26761 loadCanvas : function(src)
26763 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26767 this.imageEl = document.createElement('img');
26771 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26773 this.imageEl.src = src;
26777 onLoadCanvas : function()
26779 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26780 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26782 this.bodyEl.un('click', this.beforeSelectFile, this);
26784 this.notifyEl.hide();
26785 this.thumbEl.show();
26786 this.footerEl.show();
26788 this.baseRotateLevel();
26790 if(this.isDocument){
26791 this.setThumbBoxSize();
26794 this.setThumbBoxPosition();
26796 this.baseScaleLevel();
26802 this.canvasLoaded = true;
26805 this.maskEl.unmask();
26810 setCanvasPosition : function()
26812 if(!this.canvasEl){
26816 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26817 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26819 this.previewEl.setLeft(pw);
26820 this.previewEl.setTop(ph);
26824 onMouseDown : function(e)
26828 this.dragable = true;
26829 this.pinching = false;
26831 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26832 this.dragable = false;
26836 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26837 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26841 onMouseMove : function(e)
26845 if(!this.canvasLoaded){
26849 if (!this.dragable){
26853 var minX = Math.ceil(this.thumbEl.getLeft(true));
26854 var minY = Math.ceil(this.thumbEl.getTop(true));
26856 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26857 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26859 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26860 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26862 x = x - this.mouseX;
26863 y = y - this.mouseY;
26865 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26866 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26868 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26869 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26871 this.previewEl.setLeft(bgX);
26872 this.previewEl.setTop(bgY);
26874 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26875 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26878 onMouseUp : function(e)
26882 this.dragable = false;
26885 onMouseWheel : function(e)
26889 this.startScale = this.scale;
26891 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26893 if(!this.zoomable()){
26894 this.scale = this.startScale;
26903 zoomable : function()
26905 var minScale = this.thumbEl.getWidth() / this.minWidth;
26907 if(this.minWidth < this.minHeight){
26908 minScale = this.thumbEl.getHeight() / this.minHeight;
26911 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26912 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26916 (this.rotate == 0 || this.rotate == 180) &&
26918 width > this.imageEl.OriginWidth ||
26919 height > this.imageEl.OriginHeight ||
26920 (width < this.minWidth && height < this.minHeight)
26928 (this.rotate == 90 || this.rotate == 270) &&
26930 width > this.imageEl.OriginWidth ||
26931 height > this.imageEl.OriginHeight ||
26932 (width < this.minHeight && height < this.minWidth)
26939 !this.isDocument &&
26940 (this.rotate == 0 || this.rotate == 180) &&
26942 width < this.minWidth ||
26943 width > this.imageEl.OriginWidth ||
26944 height < this.minHeight ||
26945 height > this.imageEl.OriginHeight
26952 !this.isDocument &&
26953 (this.rotate == 90 || this.rotate == 270) &&
26955 width < this.minHeight ||
26956 width > this.imageEl.OriginWidth ||
26957 height < this.minWidth ||
26958 height > this.imageEl.OriginHeight
26968 onRotateLeft : function(e)
26970 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26972 var minScale = this.thumbEl.getWidth() / this.minWidth;
26974 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26975 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26977 this.startScale = this.scale;
26979 while (this.getScaleLevel() < minScale){
26981 this.scale = this.scale + 1;
26983 if(!this.zoomable()){
26988 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26989 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26994 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27001 this.scale = this.startScale;
27003 this.onRotateFail();
27008 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27010 if(this.isDocument){
27011 this.setThumbBoxSize();
27012 this.setThumbBoxPosition();
27013 this.setCanvasPosition();
27018 this.fireEvent('rotate', this, 'left');
27022 onRotateRight : function(e)
27024 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27026 var minScale = this.thumbEl.getWidth() / this.minWidth;
27028 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27029 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27031 this.startScale = this.scale;
27033 while (this.getScaleLevel() < minScale){
27035 this.scale = this.scale + 1;
27037 if(!this.zoomable()){
27042 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27043 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27048 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27055 this.scale = this.startScale;
27057 this.onRotateFail();
27062 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27064 if(this.isDocument){
27065 this.setThumbBoxSize();
27066 this.setThumbBoxPosition();
27067 this.setCanvasPosition();
27072 this.fireEvent('rotate', this, 'right');
27075 onRotateFail : function()
27077 this.errorEl.show(true);
27081 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27086 this.previewEl.dom.innerHTML = '';
27088 var canvasEl = document.createElement("canvas");
27090 var contextEl = canvasEl.getContext("2d");
27092 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27093 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27094 var center = this.imageEl.OriginWidth / 2;
27096 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27097 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27098 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27099 center = this.imageEl.OriginHeight / 2;
27102 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27104 contextEl.translate(center, center);
27105 contextEl.rotate(this.rotate * Math.PI / 180);
27107 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27109 this.canvasEl = document.createElement("canvas");
27111 this.contextEl = this.canvasEl.getContext("2d");
27113 switch (this.rotate) {
27116 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27117 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27119 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27124 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27125 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27127 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27128 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);
27132 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27137 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27138 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27140 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27141 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);
27145 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);
27150 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27151 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27153 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27154 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27158 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);
27165 this.previewEl.appendChild(this.canvasEl);
27167 this.setCanvasPosition();
27172 if(!this.canvasLoaded){
27176 var imageCanvas = document.createElement("canvas");
27178 var imageContext = imageCanvas.getContext("2d");
27180 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27181 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27183 var center = imageCanvas.width / 2;
27185 imageContext.translate(center, center);
27187 imageContext.rotate(this.rotate * Math.PI / 180);
27189 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27191 var canvas = document.createElement("canvas");
27193 var context = canvas.getContext("2d");
27195 canvas.width = this.minWidth;
27196 canvas.height = this.minHeight;
27198 switch (this.rotate) {
27201 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27202 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27204 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27205 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27207 var targetWidth = this.minWidth - 2 * x;
27208 var targetHeight = this.minHeight - 2 * y;
27212 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27213 scale = targetWidth / width;
27216 if(x > 0 && y == 0){
27217 scale = targetHeight / height;
27220 if(x > 0 && y > 0){
27221 scale = targetWidth / width;
27223 if(width < height){
27224 scale = targetHeight / height;
27228 context.scale(scale, scale);
27230 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27231 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27233 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27234 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27236 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27241 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27242 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27244 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27245 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27247 var targetWidth = this.minWidth - 2 * x;
27248 var targetHeight = this.minHeight - 2 * y;
27252 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27253 scale = targetWidth / width;
27256 if(x > 0 && y == 0){
27257 scale = targetHeight / height;
27260 if(x > 0 && y > 0){
27261 scale = targetWidth / width;
27263 if(width < height){
27264 scale = targetHeight / height;
27268 context.scale(scale, scale);
27270 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27271 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27273 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27274 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27276 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27278 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27283 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27284 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27286 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27287 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27289 var targetWidth = this.minWidth - 2 * x;
27290 var targetHeight = this.minHeight - 2 * y;
27294 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27295 scale = targetWidth / width;
27298 if(x > 0 && y == 0){
27299 scale = targetHeight / height;
27302 if(x > 0 && y > 0){
27303 scale = targetWidth / width;
27305 if(width < height){
27306 scale = targetHeight / height;
27310 context.scale(scale, scale);
27312 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27313 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27315 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27316 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27318 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27319 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27321 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27326 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27327 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27329 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27330 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27332 var targetWidth = this.minWidth - 2 * x;
27333 var targetHeight = this.minHeight - 2 * y;
27337 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27338 scale = targetWidth / width;
27341 if(x > 0 && y == 0){
27342 scale = targetHeight / height;
27345 if(x > 0 && y > 0){
27346 scale = targetWidth / width;
27348 if(width < height){
27349 scale = targetHeight / height;
27353 context.scale(scale, scale);
27355 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27356 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27358 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27359 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27361 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27363 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27370 this.cropData = canvas.toDataURL(this.cropType);
27372 if(this.fireEvent('crop', this, this.cropData) !== false){
27373 this.process(this.file, this.cropData);
27380 setThumbBoxSize : function()
27384 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27385 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27386 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27388 this.minWidth = width;
27389 this.minHeight = height;
27391 if(this.rotate == 90 || this.rotate == 270){
27392 this.minWidth = height;
27393 this.minHeight = width;
27398 width = Math.ceil(this.minWidth * height / this.minHeight);
27400 if(this.minWidth > this.minHeight){
27402 height = Math.ceil(this.minHeight * width / this.minWidth);
27405 this.thumbEl.setStyle({
27406 width : width + 'px',
27407 height : height + 'px'
27414 setThumbBoxPosition : function()
27416 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27417 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27419 this.thumbEl.setLeft(x);
27420 this.thumbEl.setTop(y);
27424 baseRotateLevel : function()
27426 this.baseRotate = 1;
27429 typeof(this.exif) != 'undefined' &&
27430 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27431 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27433 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27436 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27440 baseScaleLevel : function()
27444 if(this.isDocument){
27446 if(this.baseRotate == 6 || this.baseRotate == 8){
27448 height = this.thumbEl.getHeight();
27449 this.baseScale = height / this.imageEl.OriginWidth;
27451 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27452 width = this.thumbEl.getWidth();
27453 this.baseScale = width / this.imageEl.OriginHeight;
27459 height = this.thumbEl.getHeight();
27460 this.baseScale = height / this.imageEl.OriginHeight;
27462 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27463 width = this.thumbEl.getWidth();
27464 this.baseScale = width / this.imageEl.OriginWidth;
27470 if(this.baseRotate == 6 || this.baseRotate == 8){
27472 width = this.thumbEl.getHeight();
27473 this.baseScale = width / this.imageEl.OriginHeight;
27475 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27476 height = this.thumbEl.getWidth();
27477 this.baseScale = height / this.imageEl.OriginHeight;
27480 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27481 height = this.thumbEl.getWidth();
27482 this.baseScale = height / this.imageEl.OriginHeight;
27484 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27485 width = this.thumbEl.getHeight();
27486 this.baseScale = width / this.imageEl.OriginWidth;
27493 width = this.thumbEl.getWidth();
27494 this.baseScale = width / this.imageEl.OriginWidth;
27496 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27497 height = this.thumbEl.getHeight();
27498 this.baseScale = height / this.imageEl.OriginHeight;
27501 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27503 height = this.thumbEl.getHeight();
27504 this.baseScale = height / this.imageEl.OriginHeight;
27506 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27507 width = this.thumbEl.getWidth();
27508 this.baseScale = width / this.imageEl.OriginWidth;
27516 getScaleLevel : function()
27518 return this.baseScale * Math.pow(1.1, this.scale);
27521 onTouchStart : function(e)
27523 if(!this.canvasLoaded){
27524 this.beforeSelectFile(e);
27528 var touches = e.browserEvent.touches;
27534 if(touches.length == 1){
27535 this.onMouseDown(e);
27539 if(touches.length != 2){
27545 for(var i = 0, finger; finger = touches[i]; i++){
27546 coords.push(finger.pageX, finger.pageY);
27549 var x = Math.pow(coords[0] - coords[2], 2);
27550 var y = Math.pow(coords[1] - coords[3], 2);
27552 this.startDistance = Math.sqrt(x + y);
27554 this.startScale = this.scale;
27556 this.pinching = true;
27557 this.dragable = false;
27561 onTouchMove : function(e)
27563 if(!this.pinching && !this.dragable){
27567 var touches = e.browserEvent.touches;
27574 this.onMouseMove(e);
27580 for(var i = 0, finger; finger = touches[i]; i++){
27581 coords.push(finger.pageX, finger.pageY);
27584 var x = Math.pow(coords[0] - coords[2], 2);
27585 var y = Math.pow(coords[1] - coords[3], 2);
27587 this.endDistance = Math.sqrt(x + y);
27589 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27591 if(!this.zoomable()){
27592 this.scale = this.startScale;
27600 onTouchEnd : function(e)
27602 this.pinching = false;
27603 this.dragable = false;
27607 process : function(file, crop)
27610 this.maskEl.mask(this.loadingText);
27613 this.xhr = new XMLHttpRequest();
27615 file.xhr = this.xhr;
27617 this.xhr.open(this.method, this.url, true);
27620 "Accept": "application/json",
27621 "Cache-Control": "no-cache",
27622 "X-Requested-With": "XMLHttpRequest"
27625 for (var headerName in headers) {
27626 var headerValue = headers[headerName];
27628 this.xhr.setRequestHeader(headerName, headerValue);
27634 this.xhr.onload = function()
27636 _this.xhrOnLoad(_this.xhr);
27639 this.xhr.onerror = function()
27641 _this.xhrOnError(_this.xhr);
27644 var formData = new FormData();
27646 formData.append('returnHTML', 'NO');
27649 formData.append('crop', crop);
27652 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27653 formData.append(this.paramName, file, file.name);
27656 if(typeof(file.filename) != 'undefined'){
27657 formData.append('filename', file.filename);
27660 if(typeof(file.mimetype) != 'undefined'){
27661 formData.append('mimetype', file.mimetype);
27664 if(this.fireEvent('arrange', this, formData) != false){
27665 this.xhr.send(formData);
27669 xhrOnLoad : function(xhr)
27672 this.maskEl.unmask();
27675 if (xhr.readyState !== 4) {
27676 this.fireEvent('exception', this, xhr);
27680 var response = Roo.decode(xhr.responseText);
27682 if(!response.success){
27683 this.fireEvent('exception', this, xhr);
27687 var response = Roo.decode(xhr.responseText);
27689 this.fireEvent('upload', this, response);
27693 xhrOnError : function()
27696 this.maskEl.unmask();
27699 Roo.log('xhr on error');
27701 var response = Roo.decode(xhr.responseText);
27707 prepare : function(file)
27710 this.maskEl.mask(this.loadingText);
27716 if(typeof(file) === 'string'){
27717 this.loadCanvas(file);
27721 if(!file || !this.urlAPI){
27726 this.cropType = file.type;
27730 if(this.fireEvent('prepare', this, this.file) != false){
27732 var reader = new FileReader();
27734 reader.onload = function (e) {
27735 if (e.target.error) {
27736 Roo.log(e.target.error);
27740 var buffer = e.target.result,
27741 dataView = new DataView(buffer),
27743 maxOffset = dataView.byteLength - 4,
27747 if (dataView.getUint16(0) === 0xffd8) {
27748 while (offset < maxOffset) {
27749 markerBytes = dataView.getUint16(offset);
27751 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27752 markerLength = dataView.getUint16(offset + 2) + 2;
27753 if (offset + markerLength > dataView.byteLength) {
27754 Roo.log('Invalid meta data: Invalid segment size.');
27758 if(markerBytes == 0xffe1){
27759 _this.parseExifData(
27766 offset += markerLength;
27776 var url = _this.urlAPI.createObjectURL(_this.file);
27778 _this.loadCanvas(url);
27783 reader.readAsArrayBuffer(this.file);
27789 parseExifData : function(dataView, offset, length)
27791 var tiffOffset = offset + 10,
27795 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27796 // No Exif data, might be XMP data instead
27800 // Check for the ASCII code for "Exif" (0x45786966):
27801 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27802 // No Exif data, might be XMP data instead
27805 if (tiffOffset + 8 > dataView.byteLength) {
27806 Roo.log('Invalid Exif data: Invalid segment size.');
27809 // Check for the two null bytes:
27810 if (dataView.getUint16(offset + 8) !== 0x0000) {
27811 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27814 // Check the byte alignment:
27815 switch (dataView.getUint16(tiffOffset)) {
27817 littleEndian = true;
27820 littleEndian = false;
27823 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27826 // Check for the TIFF tag marker (0x002A):
27827 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27828 Roo.log('Invalid Exif data: Missing TIFF marker.');
27831 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27832 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27834 this.parseExifTags(
27837 tiffOffset + dirOffset,
27842 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27847 if (dirOffset + 6 > dataView.byteLength) {
27848 Roo.log('Invalid Exif data: Invalid directory offset.');
27851 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27852 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27853 if (dirEndOffset + 4 > dataView.byteLength) {
27854 Roo.log('Invalid Exif data: Invalid directory size.');
27857 for (i = 0; i < tagsNumber; i += 1) {
27861 dirOffset + 2 + 12 * i, // tag offset
27865 // Return the offset to the next directory:
27866 return dataView.getUint32(dirEndOffset, littleEndian);
27869 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27871 var tag = dataView.getUint16(offset, littleEndian);
27873 this.exif[tag] = this.getExifValue(
27877 dataView.getUint16(offset + 2, littleEndian), // tag type
27878 dataView.getUint32(offset + 4, littleEndian), // tag length
27883 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27885 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27894 Roo.log('Invalid Exif data: Invalid tag type.');
27898 tagSize = tagType.size * length;
27899 // Determine if the value is contained in the dataOffset bytes,
27900 // or if the value at the dataOffset is a pointer to the actual data:
27901 dataOffset = tagSize > 4 ?
27902 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27903 if (dataOffset + tagSize > dataView.byteLength) {
27904 Roo.log('Invalid Exif data: Invalid data offset.');
27907 if (length === 1) {
27908 return tagType.getValue(dataView, dataOffset, littleEndian);
27911 for (i = 0; i < length; i += 1) {
27912 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27915 if (tagType.ascii) {
27917 // Concatenate the chars:
27918 for (i = 0; i < values.length; i += 1) {
27920 // Ignore the terminating NULL byte(s):
27921 if (c === '\u0000') {
27933 Roo.apply(Roo.bootstrap.UploadCropbox, {
27935 'Orientation': 0x0112
27939 1: 0, //'top-left',
27941 3: 180, //'bottom-right',
27942 // 4: 'bottom-left',
27944 6: 90, //'right-top',
27945 // 7: 'right-bottom',
27946 8: 270 //'left-bottom'
27950 // byte, 8-bit unsigned int:
27952 getValue: function (dataView, dataOffset) {
27953 return dataView.getUint8(dataOffset);
27957 // ascii, 8-bit byte:
27959 getValue: function (dataView, dataOffset) {
27960 return String.fromCharCode(dataView.getUint8(dataOffset));
27965 // short, 16 bit int:
27967 getValue: function (dataView, dataOffset, littleEndian) {
27968 return dataView.getUint16(dataOffset, littleEndian);
27972 // long, 32 bit int:
27974 getValue: function (dataView, dataOffset, littleEndian) {
27975 return dataView.getUint32(dataOffset, littleEndian);
27979 // rational = two long values, first is numerator, second is denominator:
27981 getValue: function (dataView, dataOffset, littleEndian) {
27982 return dataView.getUint32(dataOffset, littleEndian) /
27983 dataView.getUint32(dataOffset + 4, littleEndian);
27987 // slong, 32 bit signed int:
27989 getValue: function (dataView, dataOffset, littleEndian) {
27990 return dataView.getInt32(dataOffset, littleEndian);
27994 // srational, two slongs, first is numerator, second is denominator:
27996 getValue: function (dataView, dataOffset, littleEndian) {
27997 return dataView.getInt32(dataOffset, littleEndian) /
27998 dataView.getInt32(dataOffset + 4, littleEndian);
28008 cls : 'btn-group roo-upload-cropbox-rotate-left',
28009 action : 'rotate-left',
28013 cls : 'btn btn-default',
28014 html : '<i class="fa fa-undo"></i>'
28020 cls : 'btn-group roo-upload-cropbox-picture',
28021 action : 'picture',
28025 cls : 'btn btn-default',
28026 html : '<i class="fa fa-picture-o"></i>'
28032 cls : 'btn-group roo-upload-cropbox-rotate-right',
28033 action : 'rotate-right',
28037 cls : 'btn btn-default',
28038 html : '<i class="fa fa-repeat"></i>'
28046 cls : 'btn-group roo-upload-cropbox-rotate-left',
28047 action : 'rotate-left',
28051 cls : 'btn btn-default',
28052 html : '<i class="fa fa-undo"></i>'
28058 cls : 'btn-group roo-upload-cropbox-download',
28059 action : 'download',
28063 cls : 'btn btn-default',
28064 html : '<i class="fa fa-download"></i>'
28070 cls : 'btn-group roo-upload-cropbox-crop',
28075 cls : 'btn btn-default',
28076 html : '<i class="fa fa-crop"></i>'
28082 cls : 'btn-group roo-upload-cropbox-trash',
28087 cls : 'btn btn-default',
28088 html : '<i class="fa fa-trash"></i>'
28094 cls : 'btn-group roo-upload-cropbox-rotate-right',
28095 action : 'rotate-right',
28099 cls : 'btn btn-default',
28100 html : '<i class="fa fa-repeat"></i>'
28108 cls : 'btn-group roo-upload-cropbox-rotate-left',
28109 action : 'rotate-left',
28113 cls : 'btn btn-default',
28114 html : '<i class="fa fa-undo"></i>'
28120 cls : 'btn-group roo-upload-cropbox-rotate-right',
28121 action : 'rotate-right',
28125 cls : 'btn btn-default',
28126 html : '<i class="fa fa-repeat"></i>'
28139 * @class Roo.bootstrap.DocumentManager
28140 * @extends Roo.bootstrap.Component
28141 * Bootstrap DocumentManager class
28142 * @cfg {String} paramName default 'imageUpload'
28143 * @cfg {String} toolTipName default 'filename'
28144 * @cfg {String} method default POST
28145 * @cfg {String} url action url
28146 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28147 * @cfg {Boolean} multiple multiple upload default true
28148 * @cfg {Number} thumbSize default 300
28149 * @cfg {String} fieldLabel
28150 * @cfg {Number} labelWidth default 4
28151 * @cfg {String} labelAlign (left|top) default left
28152 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28153 * @cfg {Number} labellg set the width of label (1-12)
28154 * @cfg {Number} labelmd set the width of label (1-12)
28155 * @cfg {Number} labelsm set the width of label (1-12)
28156 * @cfg {Number} labelxs set the width of label (1-12)
28159 * Create a new DocumentManager
28160 * @param {Object} config The config object
28163 Roo.bootstrap.DocumentManager = function(config){
28164 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28167 this.delegates = [];
28172 * Fire when initial the DocumentManager
28173 * @param {Roo.bootstrap.DocumentManager} this
28178 * inspect selected file
28179 * @param {Roo.bootstrap.DocumentManager} this
28180 * @param {File} file
28185 * Fire when xhr load exception
28186 * @param {Roo.bootstrap.DocumentManager} this
28187 * @param {XMLHttpRequest} xhr
28189 "exception" : true,
28191 * @event afterupload
28192 * Fire when xhr load exception
28193 * @param {Roo.bootstrap.DocumentManager} this
28194 * @param {XMLHttpRequest} xhr
28196 "afterupload" : true,
28199 * prepare the form data
28200 * @param {Roo.bootstrap.DocumentManager} this
28201 * @param {Object} formData
28206 * Fire when remove the file
28207 * @param {Roo.bootstrap.DocumentManager} this
28208 * @param {Object} file
28213 * Fire after refresh the file
28214 * @param {Roo.bootstrap.DocumentManager} this
28219 * Fire after click the image
28220 * @param {Roo.bootstrap.DocumentManager} this
28221 * @param {Object} file
28226 * Fire when upload a image and editable set to true
28227 * @param {Roo.bootstrap.DocumentManager} this
28228 * @param {Object} file
28232 * @event beforeselectfile
28233 * Fire before select file
28234 * @param {Roo.bootstrap.DocumentManager} this
28236 "beforeselectfile" : true,
28239 * Fire before process file
28240 * @param {Roo.bootstrap.DocumentManager} this
28241 * @param {Object} file
28248 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28257 paramName : 'imageUpload',
28258 toolTipName : 'filename',
28261 labelAlign : 'left',
28271 getAutoCreate : function()
28273 var managerWidget = {
28275 cls : 'roo-document-manager',
28279 cls : 'roo-document-manager-selector',
28284 cls : 'roo-document-manager-uploader',
28288 cls : 'roo-document-manager-upload-btn',
28289 html : '<i class="fa fa-plus"></i>'
28300 cls : 'column col-md-12',
28305 if(this.fieldLabel.length){
28310 cls : 'column col-md-12',
28311 html : this.fieldLabel
28315 cls : 'column col-md-12',
28320 if(this.labelAlign == 'left'){
28325 html : this.fieldLabel
28334 if(this.labelWidth > 12){
28335 content[0].style = "width: " + this.labelWidth + 'px';
28338 if(this.labelWidth < 13 && this.labelmd == 0){
28339 this.labelmd = this.labelWidth;
28342 if(this.labellg > 0){
28343 content[0].cls += ' col-lg-' + this.labellg;
28344 content[1].cls += ' col-lg-' + (12 - this.labellg);
28347 if(this.labelmd > 0){
28348 content[0].cls += ' col-md-' + this.labelmd;
28349 content[1].cls += ' col-md-' + (12 - this.labelmd);
28352 if(this.labelsm > 0){
28353 content[0].cls += ' col-sm-' + this.labelsm;
28354 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28357 if(this.labelxs > 0){
28358 content[0].cls += ' col-xs-' + this.labelxs;
28359 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28367 cls : 'row clearfix',
28375 initEvents : function()
28377 this.managerEl = this.el.select('.roo-document-manager', true).first();
28378 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28380 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28381 this.selectorEl.hide();
28384 this.selectorEl.attr('multiple', 'multiple');
28387 this.selectorEl.on('change', this.onFileSelected, this);
28389 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28390 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28392 this.uploader.on('click', this.onUploaderClick, this);
28394 this.renderProgressDialog();
28398 window.addEventListener("resize", function() { _this.refresh(); } );
28400 this.fireEvent('initial', this);
28403 renderProgressDialog : function()
28407 this.progressDialog = new Roo.bootstrap.Modal({
28408 cls : 'roo-document-manager-progress-dialog',
28409 allow_close : false,
28419 btnclick : function() {
28420 _this.uploadCancel();
28426 this.progressDialog.render(Roo.get(document.body));
28428 this.progress = new Roo.bootstrap.Progress({
28429 cls : 'roo-document-manager-progress',
28434 this.progress.render(this.progressDialog.getChildContainer());
28436 this.progressBar = new Roo.bootstrap.ProgressBar({
28437 cls : 'roo-document-manager-progress-bar',
28440 aria_valuemax : 12,
28444 this.progressBar.render(this.progress.getChildContainer());
28447 onUploaderClick : function(e)
28449 e.preventDefault();
28451 if(this.fireEvent('beforeselectfile', this) != false){
28452 this.selectorEl.dom.click();
28457 onFileSelected : function(e)
28459 e.preventDefault();
28461 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28465 Roo.each(this.selectorEl.dom.files, function(file){
28466 if(this.fireEvent('inspect', this, file) != false){
28467 this.files.push(file);
28477 this.selectorEl.dom.value = '';
28479 if(!this.files.length){
28483 if(this.boxes > 0 && this.files.length > this.boxes){
28484 this.files = this.files.slice(0, this.boxes);
28487 this.uploader.show();
28489 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28490 this.uploader.hide();
28499 Roo.each(this.files, function(file){
28501 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28502 var f = this.renderPreview(file);
28507 if(file.type.indexOf('image') != -1){
28508 this.delegates.push(
28510 _this.process(file);
28511 }).createDelegate(this)
28519 _this.process(file);
28520 }).createDelegate(this)
28525 this.files = files;
28527 this.delegates = this.delegates.concat(docs);
28529 if(!this.delegates.length){
28534 this.progressBar.aria_valuemax = this.delegates.length;
28541 arrange : function()
28543 if(!this.delegates.length){
28544 this.progressDialog.hide();
28549 var delegate = this.delegates.shift();
28551 this.progressDialog.show();
28553 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28555 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28560 refresh : function()
28562 this.uploader.show();
28564 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28565 this.uploader.hide();
28568 Roo.isTouch ? this.closable(false) : this.closable(true);
28570 this.fireEvent('refresh', this);
28573 onRemove : function(e, el, o)
28575 e.preventDefault();
28577 this.fireEvent('remove', this, o);
28581 remove : function(o)
28585 Roo.each(this.files, function(file){
28586 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28595 this.files = files;
28602 Roo.each(this.files, function(file){
28607 file.target.remove();
28616 onClick : function(e, el, o)
28618 e.preventDefault();
28620 this.fireEvent('click', this, o);
28624 closable : function(closable)
28626 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28628 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28640 xhrOnLoad : function(xhr)
28642 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28646 if (xhr.readyState !== 4) {
28648 this.fireEvent('exception', this, xhr);
28652 var response = Roo.decode(xhr.responseText);
28654 if(!response.success){
28656 this.fireEvent('exception', this, xhr);
28660 var file = this.renderPreview(response.data);
28662 this.files.push(file);
28666 this.fireEvent('afterupload', this, xhr);
28670 xhrOnError : function(xhr)
28672 Roo.log('xhr on error');
28674 var response = Roo.decode(xhr.responseText);
28681 process : function(file)
28683 if(this.fireEvent('process', this, file) !== false){
28684 if(this.editable && file.type.indexOf('image') != -1){
28685 this.fireEvent('edit', this, file);
28689 this.uploadStart(file, false);
28696 uploadStart : function(file, crop)
28698 this.xhr = new XMLHttpRequest();
28700 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28705 file.xhr = this.xhr;
28707 this.managerEl.createChild({
28709 cls : 'roo-document-manager-loading',
28713 tooltip : file.name,
28714 cls : 'roo-document-manager-thumb',
28715 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28721 this.xhr.open(this.method, this.url, true);
28724 "Accept": "application/json",
28725 "Cache-Control": "no-cache",
28726 "X-Requested-With": "XMLHttpRequest"
28729 for (var headerName in headers) {
28730 var headerValue = headers[headerName];
28732 this.xhr.setRequestHeader(headerName, headerValue);
28738 this.xhr.onload = function()
28740 _this.xhrOnLoad(_this.xhr);
28743 this.xhr.onerror = function()
28745 _this.xhrOnError(_this.xhr);
28748 var formData = new FormData();
28750 formData.append('returnHTML', 'NO');
28753 formData.append('crop', crop);
28756 formData.append(this.paramName, file, file.name);
28763 if(this.fireEvent('prepare', this, formData, options) != false){
28765 if(options.manually){
28769 this.xhr.send(formData);
28773 this.uploadCancel();
28776 uploadCancel : function()
28782 this.delegates = [];
28784 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28791 renderPreview : function(file)
28793 if(typeof(file.target) != 'undefined' && file.target){
28797 var previewEl = this.managerEl.createChild({
28799 cls : 'roo-document-manager-preview',
28803 tooltip : file[this.toolTipName],
28804 cls : 'roo-document-manager-thumb',
28805 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28810 html : '<i class="fa fa-times-circle"></i>'
28815 var close = previewEl.select('button.close', true).first();
28817 close.on('click', this.onRemove, this, file);
28819 file.target = previewEl;
28821 var image = previewEl.select('img', true).first();
28825 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28827 image.on('click', this.onClick, this, file);
28833 onPreviewLoad : function(file, image)
28835 if(typeof(file.target) == 'undefined' || !file.target){
28839 var width = image.dom.naturalWidth || image.dom.width;
28840 var height = image.dom.naturalHeight || image.dom.height;
28842 if(width > height){
28843 file.target.addClass('wide');
28847 file.target.addClass('tall');
28852 uploadFromSource : function(file, crop)
28854 this.xhr = new XMLHttpRequest();
28856 this.managerEl.createChild({
28858 cls : 'roo-document-manager-loading',
28862 tooltip : file.name,
28863 cls : 'roo-document-manager-thumb',
28864 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28870 this.xhr.open(this.method, this.url, true);
28873 "Accept": "application/json",
28874 "Cache-Control": "no-cache",
28875 "X-Requested-With": "XMLHttpRequest"
28878 for (var headerName in headers) {
28879 var headerValue = headers[headerName];
28881 this.xhr.setRequestHeader(headerName, headerValue);
28887 this.xhr.onload = function()
28889 _this.xhrOnLoad(_this.xhr);
28892 this.xhr.onerror = function()
28894 _this.xhrOnError(_this.xhr);
28897 var formData = new FormData();
28899 formData.append('returnHTML', 'NO');
28901 formData.append('crop', crop);
28903 if(typeof(file.filename) != 'undefined'){
28904 formData.append('filename', file.filename);
28907 if(typeof(file.mimetype) != 'undefined'){
28908 formData.append('mimetype', file.mimetype);
28913 if(this.fireEvent('prepare', this, formData) != false){
28914 this.xhr.send(formData);
28924 * @class Roo.bootstrap.DocumentViewer
28925 * @extends Roo.bootstrap.Component
28926 * Bootstrap DocumentViewer class
28927 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28928 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28931 * Create a new DocumentViewer
28932 * @param {Object} config The config object
28935 Roo.bootstrap.DocumentViewer = function(config){
28936 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28941 * Fire after initEvent
28942 * @param {Roo.bootstrap.DocumentViewer} this
28948 * @param {Roo.bootstrap.DocumentViewer} this
28953 * Fire after download button
28954 * @param {Roo.bootstrap.DocumentViewer} this
28959 * Fire after trash button
28960 * @param {Roo.bootstrap.DocumentViewer} this
28967 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28969 showDownload : true,
28973 getAutoCreate : function()
28977 cls : 'roo-document-viewer',
28981 cls : 'roo-document-viewer-body',
28985 cls : 'roo-document-viewer-thumb',
28989 cls : 'roo-document-viewer-image'
28997 cls : 'roo-document-viewer-footer',
29000 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29004 cls : 'btn-group roo-document-viewer-download',
29008 cls : 'btn btn-default',
29009 html : '<i class="fa fa-download"></i>'
29015 cls : 'btn-group roo-document-viewer-trash',
29019 cls : 'btn btn-default',
29020 html : '<i class="fa fa-trash"></i>'
29033 initEvents : function()
29035 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29036 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29038 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29039 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29041 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29042 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29044 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29045 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29047 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29048 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29050 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29051 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29053 this.bodyEl.on('click', this.onClick, this);
29054 this.downloadBtn.on('click', this.onDownload, this);
29055 this.trashBtn.on('click', this.onTrash, this);
29057 this.downloadBtn.hide();
29058 this.trashBtn.hide();
29060 if(this.showDownload){
29061 this.downloadBtn.show();
29064 if(this.showTrash){
29065 this.trashBtn.show();
29068 if(!this.showDownload && !this.showTrash) {
29069 this.footerEl.hide();
29074 initial : function()
29076 this.fireEvent('initial', this);
29080 onClick : function(e)
29082 e.preventDefault();
29084 this.fireEvent('click', this);
29087 onDownload : function(e)
29089 e.preventDefault();
29091 this.fireEvent('download', this);
29094 onTrash : function(e)
29096 e.preventDefault();
29098 this.fireEvent('trash', this);
29110 * @class Roo.bootstrap.NavProgressBar
29111 * @extends Roo.bootstrap.Component
29112 * Bootstrap NavProgressBar class
29115 * Create a new nav progress bar
29116 * @param {Object} config The config object
29119 Roo.bootstrap.NavProgressBar = function(config){
29120 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29122 this.bullets = this.bullets || [];
29124 // Roo.bootstrap.NavProgressBar.register(this);
29128 * Fires when the active item changes
29129 * @param {Roo.bootstrap.NavProgressBar} this
29130 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29131 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29138 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29143 getAutoCreate : function()
29145 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29149 cls : 'roo-navigation-bar-group',
29153 cls : 'roo-navigation-top-bar'
29157 cls : 'roo-navigation-bullets-bar',
29161 cls : 'roo-navigation-bar'
29168 cls : 'roo-navigation-bottom-bar'
29178 initEvents: function()
29183 onRender : function(ct, position)
29185 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29187 if(this.bullets.length){
29188 Roo.each(this.bullets, function(b){
29197 addItem : function(cfg)
29199 var item = new Roo.bootstrap.NavProgressItem(cfg);
29201 item.parentId = this.id;
29202 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29205 var top = new Roo.bootstrap.Element({
29207 cls : 'roo-navigation-bar-text'
29210 var bottom = new Roo.bootstrap.Element({
29212 cls : 'roo-navigation-bar-text'
29215 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29216 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29218 var topText = new Roo.bootstrap.Element({
29220 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29223 var bottomText = new Roo.bootstrap.Element({
29225 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29228 topText.onRender(top.el, null);
29229 bottomText.onRender(bottom.el, null);
29232 item.bottomEl = bottom;
29235 this.barItems.push(item);
29240 getActive : function()
29242 var active = false;
29244 Roo.each(this.barItems, function(v){
29246 if (!v.isActive()) {
29258 setActiveItem : function(item)
29262 Roo.each(this.barItems, function(v){
29263 if (v.rid == item.rid) {
29267 if (v.isActive()) {
29268 v.setActive(false);
29273 item.setActive(true);
29275 this.fireEvent('changed', this, item, prev);
29278 getBarItem: function(rid)
29282 Roo.each(this.barItems, function(e) {
29283 if (e.rid != rid) {
29294 indexOfItem : function(item)
29298 Roo.each(this.barItems, function(v, i){
29300 if (v.rid != item.rid) {
29311 setActiveNext : function()
29313 var i = this.indexOfItem(this.getActive());
29315 if (i > this.barItems.length) {
29319 this.setActiveItem(this.barItems[i+1]);
29322 setActivePrev : function()
29324 var i = this.indexOfItem(this.getActive());
29330 this.setActiveItem(this.barItems[i-1]);
29333 format : function()
29335 if(!this.barItems.length){
29339 var width = 100 / this.barItems.length;
29341 Roo.each(this.barItems, function(i){
29342 i.el.setStyle('width', width + '%');
29343 i.topEl.el.setStyle('width', width + '%');
29344 i.bottomEl.el.setStyle('width', width + '%');
29353 * Nav Progress Item
29358 * @class Roo.bootstrap.NavProgressItem
29359 * @extends Roo.bootstrap.Component
29360 * Bootstrap NavProgressItem class
29361 * @cfg {String} rid the reference id
29362 * @cfg {Boolean} active (true|false) Is item active default false
29363 * @cfg {Boolean} disabled (true|false) Is item active default false
29364 * @cfg {String} html
29365 * @cfg {String} position (top|bottom) text position default bottom
29366 * @cfg {String} icon show icon instead of number
29369 * Create a new NavProgressItem
29370 * @param {Object} config The config object
29372 Roo.bootstrap.NavProgressItem = function(config){
29373 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29378 * The raw click event for the entire grid.
29379 * @param {Roo.bootstrap.NavProgressItem} this
29380 * @param {Roo.EventObject} e
29387 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29393 position : 'bottom',
29396 getAutoCreate : function()
29398 var iconCls = 'roo-navigation-bar-item-icon';
29400 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29404 cls: 'roo-navigation-bar-item',
29414 cfg.cls += ' active';
29417 cfg.cls += ' disabled';
29423 disable : function()
29425 this.setDisabled(true);
29428 enable : function()
29430 this.setDisabled(false);
29433 initEvents: function()
29435 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29437 this.iconEl.on('click', this.onClick, this);
29440 onClick : function(e)
29442 e.preventDefault();
29448 if(this.fireEvent('click', this, e) === false){
29452 this.parent().setActiveItem(this);
29455 isActive: function ()
29457 return this.active;
29460 setActive : function(state)
29462 if(this.active == state){
29466 this.active = state;
29469 this.el.addClass('active');
29473 this.el.removeClass('active');
29478 setDisabled : function(state)
29480 if(this.disabled == state){
29484 this.disabled = state;
29487 this.el.addClass('disabled');
29491 this.el.removeClass('disabled');
29494 tooltipEl : function()
29496 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29509 * @class Roo.bootstrap.FieldLabel
29510 * @extends Roo.bootstrap.Component
29511 * Bootstrap FieldLabel class
29512 * @cfg {String} html contents of the element
29513 * @cfg {String} tag tag of the element default label
29514 * @cfg {String} cls class of the element
29515 * @cfg {String} target label target
29516 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29517 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29518 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29519 * @cfg {String} iconTooltip default "This field is required"
29522 * Create a new FieldLabel
29523 * @param {Object} config The config object
29526 Roo.bootstrap.FieldLabel = function(config){
29527 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29532 * Fires after the field has been marked as invalid.
29533 * @param {Roo.form.FieldLabel} this
29534 * @param {String} msg The validation message
29539 * Fires after the field has been validated with no errors.
29540 * @param {Roo.form.FieldLabel} this
29546 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29553 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29554 validClass : 'text-success fa fa-lg fa-check',
29555 iconTooltip : 'This field is required',
29557 getAutoCreate : function(){
29561 cls : 'roo-bootstrap-field-label ' + this.cls,
29567 tooltip : this.iconTooltip
29579 initEvents: function()
29581 Roo.bootstrap.Element.superclass.initEvents.call(this);
29583 this.iconEl = this.el.select('i', true).first();
29585 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29587 Roo.bootstrap.FieldLabel.register(this);
29591 * Mark this field as valid
29593 markValid : function()
29595 this.iconEl.show();
29597 this.iconEl.removeClass(this.invalidClass);
29599 this.iconEl.addClass(this.validClass);
29601 this.fireEvent('valid', this);
29605 * Mark this field as invalid
29606 * @param {String} msg The validation message
29608 markInvalid : function(msg)
29610 this.iconEl.show();
29612 this.iconEl.removeClass(this.validClass);
29614 this.iconEl.addClass(this.invalidClass);
29616 this.fireEvent('invalid', this, msg);
29622 Roo.apply(Roo.bootstrap.FieldLabel, {
29627 * register a FieldLabel Group
29628 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29630 register : function(label)
29632 if(this.groups.hasOwnProperty(label.target)){
29636 this.groups[label.target] = label;
29640 * fetch a FieldLabel Group based on the target
29641 * @param {string} target
29642 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29644 get: function(target) {
29645 if (typeof(this.groups[target]) == 'undefined') {
29649 return this.groups[target] ;
29658 * page DateSplitField.
29664 * @class Roo.bootstrap.DateSplitField
29665 * @extends Roo.bootstrap.Component
29666 * Bootstrap DateSplitField class
29667 * @cfg {string} fieldLabel - the label associated
29668 * @cfg {Number} labelWidth set the width of label (0-12)
29669 * @cfg {String} labelAlign (top|left)
29670 * @cfg {Boolean} dayAllowBlank (true|false) default false
29671 * @cfg {Boolean} monthAllowBlank (true|false) default false
29672 * @cfg {Boolean} yearAllowBlank (true|false) default false
29673 * @cfg {string} dayPlaceholder
29674 * @cfg {string} monthPlaceholder
29675 * @cfg {string} yearPlaceholder
29676 * @cfg {string} dayFormat default 'd'
29677 * @cfg {string} monthFormat default 'm'
29678 * @cfg {string} yearFormat default 'Y'
29679 * @cfg {Number} labellg set the width of label (1-12)
29680 * @cfg {Number} labelmd set the width of label (1-12)
29681 * @cfg {Number} labelsm set the width of label (1-12)
29682 * @cfg {Number} labelxs set the width of label (1-12)
29686 * Create a new DateSplitField
29687 * @param {Object} config The config object
29690 Roo.bootstrap.DateSplitField = function(config){
29691 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29697 * getting the data of years
29698 * @param {Roo.bootstrap.DateSplitField} this
29699 * @param {Object} years
29704 * getting the data of days
29705 * @param {Roo.bootstrap.DateSplitField} this
29706 * @param {Object} days
29711 * Fires after the field has been marked as invalid.
29712 * @param {Roo.form.Field} this
29713 * @param {String} msg The validation message
29718 * Fires after the field has been validated with no errors.
29719 * @param {Roo.form.Field} this
29725 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29728 labelAlign : 'top',
29730 dayAllowBlank : false,
29731 monthAllowBlank : false,
29732 yearAllowBlank : false,
29733 dayPlaceholder : '',
29734 monthPlaceholder : '',
29735 yearPlaceholder : '',
29739 isFormField : true,
29745 getAutoCreate : function()
29749 cls : 'row roo-date-split-field-group',
29754 cls : 'form-hidden-field roo-date-split-field-group-value',
29760 var labelCls = 'col-md-12';
29761 var contentCls = 'col-md-4';
29763 if(this.fieldLabel){
29767 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29771 html : this.fieldLabel
29776 if(this.labelAlign == 'left'){
29778 if(this.labelWidth > 12){
29779 label.style = "width: " + this.labelWidth + 'px';
29782 if(this.labelWidth < 13 && this.labelmd == 0){
29783 this.labelmd = this.labelWidth;
29786 if(this.labellg > 0){
29787 labelCls = ' col-lg-' + this.labellg;
29788 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29791 if(this.labelmd > 0){
29792 labelCls = ' col-md-' + this.labelmd;
29793 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29796 if(this.labelsm > 0){
29797 labelCls = ' col-sm-' + this.labelsm;
29798 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29801 if(this.labelxs > 0){
29802 labelCls = ' col-xs-' + this.labelxs;
29803 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29807 label.cls += ' ' + labelCls;
29809 cfg.cn.push(label);
29812 Roo.each(['day', 'month', 'year'], function(t){
29815 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29822 inputEl: function ()
29824 return this.el.select('.roo-date-split-field-group-value', true).first();
29827 onRender : function(ct, position)
29831 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29833 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29835 this.dayField = new Roo.bootstrap.ComboBox({
29836 allowBlank : this.dayAllowBlank,
29837 alwaysQuery : true,
29838 displayField : 'value',
29841 forceSelection : true,
29843 placeholder : this.dayPlaceholder,
29844 selectOnFocus : true,
29845 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29846 triggerAction : 'all',
29848 valueField : 'value',
29849 store : new Roo.data.SimpleStore({
29850 data : (function() {
29852 _this.fireEvent('days', _this, days);
29855 fields : [ 'value' ]
29858 select : function (_self, record, index)
29860 _this.setValue(_this.getValue());
29865 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29867 this.monthField = new Roo.bootstrap.MonthField({
29868 after : '<i class=\"fa fa-calendar\"></i>',
29869 allowBlank : this.monthAllowBlank,
29870 placeholder : this.monthPlaceholder,
29873 render : function (_self)
29875 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29876 e.preventDefault();
29880 select : function (_self, oldvalue, newvalue)
29882 _this.setValue(_this.getValue());
29887 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29889 this.yearField = new Roo.bootstrap.ComboBox({
29890 allowBlank : this.yearAllowBlank,
29891 alwaysQuery : true,
29892 displayField : 'value',
29895 forceSelection : true,
29897 placeholder : this.yearPlaceholder,
29898 selectOnFocus : true,
29899 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29900 triggerAction : 'all',
29902 valueField : 'value',
29903 store : new Roo.data.SimpleStore({
29904 data : (function() {
29906 _this.fireEvent('years', _this, years);
29909 fields : [ 'value' ]
29912 select : function (_self, record, index)
29914 _this.setValue(_this.getValue());
29919 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29922 setValue : function(v, format)
29924 this.inputEl.dom.value = v;
29926 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29928 var d = Date.parseDate(v, f);
29935 this.setDay(d.format(this.dayFormat));
29936 this.setMonth(d.format(this.monthFormat));
29937 this.setYear(d.format(this.yearFormat));
29944 setDay : function(v)
29946 this.dayField.setValue(v);
29947 this.inputEl.dom.value = this.getValue();
29952 setMonth : function(v)
29954 this.monthField.setValue(v, true);
29955 this.inputEl.dom.value = this.getValue();
29960 setYear : function(v)
29962 this.yearField.setValue(v);
29963 this.inputEl.dom.value = this.getValue();
29968 getDay : function()
29970 return this.dayField.getValue();
29973 getMonth : function()
29975 return this.monthField.getValue();
29978 getYear : function()
29980 return this.yearField.getValue();
29983 getValue : function()
29985 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29987 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29997 this.inputEl.dom.value = '';
30002 validate : function()
30004 var d = this.dayField.validate();
30005 var m = this.monthField.validate();
30006 var y = this.yearField.validate();
30011 (!this.dayAllowBlank && !d) ||
30012 (!this.monthAllowBlank && !m) ||
30013 (!this.yearAllowBlank && !y)
30018 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30027 this.markInvalid();
30032 markValid : function()
30035 var label = this.el.select('label', true).first();
30036 var icon = this.el.select('i.fa-star', true).first();
30042 this.fireEvent('valid', this);
30046 * Mark this field as invalid
30047 * @param {String} msg The validation message
30049 markInvalid : function(msg)
30052 var label = this.el.select('label', true).first();
30053 var icon = this.el.select('i.fa-star', true).first();
30055 if(label && !icon){
30056 this.el.select('.roo-date-split-field-label', true).createChild({
30058 cls : 'text-danger fa fa-lg fa-star',
30059 tooltip : 'This field is required',
30060 style : 'margin-right:5px;'
30064 this.fireEvent('invalid', this, msg);
30067 clearInvalid : function()
30069 var label = this.el.select('label', true).first();
30070 var icon = this.el.select('i.fa-star', true).first();
30076 this.fireEvent('valid', this);
30079 getName: function()
30089 * http://masonry.desandro.com
30091 * The idea is to render all the bricks based on vertical width...
30093 * The original code extends 'outlayer' - we might need to use that....
30099 * @class Roo.bootstrap.LayoutMasonry
30100 * @extends Roo.bootstrap.Component
30101 * Bootstrap Layout Masonry class
30104 * Create a new Element
30105 * @param {Object} config The config object
30108 Roo.bootstrap.LayoutMasonry = function(config){
30109 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30117 * Fire after layout the items
30118 * @param {Roo.bootstrap.LayoutMasonry} this
30119 * @param {Roo.EventObject} e
30126 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30129 * @cfg {Boolean} isLayoutInstant = no animation?
30131 isLayoutInstant : false, // needed?
30134 * @cfg {Number} boxWidth width of the columns
30139 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30144 * @cfg {Number} padWidth padding below box..
30149 * @cfg {Number} gutter gutter width..
30154 * @cfg {Number} maxCols maximum number of columns
30160 * @cfg {Boolean} isAutoInitial defalut true
30162 isAutoInitial : true,
30167 * @cfg {Boolean} isHorizontal defalut false
30169 isHorizontal : false,
30171 currentSize : null,
30177 bricks: null, //CompositeElement
30181 _isLayoutInited : false,
30183 // isAlternative : false, // only use for vertical layout...
30186 * @cfg {Number} alternativePadWidth padding below box..
30188 alternativePadWidth : 50,
30190 selectedBrick : [],
30192 getAutoCreate : function(){
30196 cls: 'blog-masonary-wrapper ' + this.cls,
30198 cls : 'mas-boxes masonary'
30205 getChildContainer: function( )
30207 if (this.boxesEl) {
30208 return this.boxesEl;
30211 this.boxesEl = this.el.select('.mas-boxes').first();
30213 return this.boxesEl;
30217 initEvents : function()
30221 if(this.isAutoInitial){
30222 Roo.log('hook children rendered');
30223 this.on('childrenrendered', function() {
30224 Roo.log('children rendered');
30230 initial : function()
30232 this.currentSize = this.el.getBox(true);
30234 Roo.EventManager.onWindowResize(this.resize, this);
30236 if(!this.isAutoInitial){
30244 //this.layout.defer(500,this);
30248 resize : function()
30250 var cs = this.el.getBox(true);
30253 this.currentSize.width == cs.width &&
30254 this.currentSize.x == cs.x &&
30255 this.currentSize.height == cs.height &&
30256 this.currentSize.y == cs.y
30258 Roo.log("no change in with or X or Y");
30262 this.currentSize = cs;
30268 layout : function()
30270 this._resetLayout();
30272 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30274 this.layoutItems( isInstant );
30276 this._isLayoutInited = true;
30278 this.fireEvent('layout', this);
30282 _resetLayout : function()
30284 if(this.isHorizontal){
30285 this.horizontalMeasureColumns();
30289 this.verticalMeasureColumns();
30293 verticalMeasureColumns : function()
30295 this.getContainerWidth();
30297 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30298 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30302 var boxWidth = this.boxWidth + this.padWidth;
30304 if(this.containerWidth < this.boxWidth){
30305 boxWidth = this.containerWidth
30308 var containerWidth = this.containerWidth;
30310 var cols = Math.floor(containerWidth / boxWidth);
30312 this.cols = Math.max( cols, 1 );
30314 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30316 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30318 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30320 this.colWidth = boxWidth + avail - this.padWidth;
30322 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
30323 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30326 horizontalMeasureColumns : function()
30328 this.getContainerWidth();
30330 var boxWidth = this.boxWidth;
30332 if(this.containerWidth < boxWidth){
30333 boxWidth = this.containerWidth;
30336 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30338 this.el.setHeight(boxWidth);
30342 getContainerWidth : function()
30344 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30347 layoutItems : function( isInstant )
30349 Roo.log(this.bricks);
30351 var items = Roo.apply([], this.bricks);
30353 if(this.isHorizontal){
30354 this._horizontalLayoutItems( items , isInstant );
30358 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30359 // this._verticalAlternativeLayoutItems( items , isInstant );
30363 this._verticalLayoutItems( items , isInstant );
30367 _verticalLayoutItems : function ( items , isInstant)
30369 if ( !items || !items.length ) {
30374 ['xs', 'xs', 'xs', 'tall'],
30375 ['xs', 'xs', 'tall'],
30376 ['xs', 'xs', 'sm'],
30377 ['xs', 'xs', 'xs'],
30383 ['sm', 'xs', 'xs'],
30387 ['tall', 'xs', 'xs', 'xs'],
30388 ['tall', 'xs', 'xs'],
30400 Roo.each(items, function(item, k){
30402 switch (item.size) {
30403 // these layouts take up a full box,
30414 boxes.push([item]);
30437 var filterPattern = function(box, length)
30445 var pattern = box.slice(0, length);
30449 Roo.each(pattern, function(i){
30450 format.push(i.size);
30453 Roo.each(standard, function(s){
30455 if(String(s) != String(format)){
30464 if(!match && length == 1){
30469 filterPattern(box, length - 1);
30473 queue.push(pattern);
30475 box = box.slice(length, box.length);
30477 filterPattern(box, 4);
30483 Roo.each(boxes, function(box, k){
30489 if(box.length == 1){
30494 filterPattern(box, 4);
30498 this._processVerticalLayoutQueue( queue, isInstant );
30502 // _verticalAlternativeLayoutItems : function( items , isInstant )
30504 // if ( !items || !items.length ) {
30508 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30512 _horizontalLayoutItems : function ( items , isInstant)
30514 if ( !items || !items.length || items.length < 3) {
30520 var eItems = items.slice(0, 3);
30522 items = items.slice(3, items.length);
30525 ['xs', 'xs', 'xs', 'wide'],
30526 ['xs', 'xs', 'wide'],
30527 ['xs', 'xs', 'sm'],
30528 ['xs', 'xs', 'xs'],
30534 ['sm', 'xs', 'xs'],
30538 ['wide', 'xs', 'xs', 'xs'],
30539 ['wide', 'xs', 'xs'],
30552 Roo.each(items, function(item, k){
30554 switch (item.size) {
30565 boxes.push([item]);
30589 var filterPattern = function(box, length)
30597 var pattern = box.slice(0, length);
30601 Roo.each(pattern, function(i){
30602 format.push(i.size);
30605 Roo.each(standard, function(s){
30607 if(String(s) != String(format)){
30616 if(!match && length == 1){
30621 filterPattern(box, length - 1);
30625 queue.push(pattern);
30627 box = box.slice(length, box.length);
30629 filterPattern(box, 4);
30635 Roo.each(boxes, function(box, k){
30641 if(box.length == 1){
30646 filterPattern(box, 4);
30653 var pos = this.el.getBox(true);
30657 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30659 var hit_end = false;
30661 Roo.each(queue, function(box){
30665 Roo.each(box, function(b){
30667 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30677 Roo.each(box, function(b){
30679 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30682 mx = Math.max(mx, b.x);
30686 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30690 Roo.each(box, function(b){
30692 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30706 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30709 /** Sets position of item in DOM
30710 * @param {Element} item
30711 * @param {Number} x - horizontal position
30712 * @param {Number} y - vertical position
30713 * @param {Boolean} isInstant - disables transitions
30715 _processVerticalLayoutQueue : function( queue, isInstant )
30717 var pos = this.el.getBox(true);
30722 for (var i = 0; i < this.cols; i++){
30726 Roo.each(queue, function(box, k){
30728 var col = k % this.cols;
30730 Roo.each(box, function(b,kk){
30732 b.el.position('absolute');
30734 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30735 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30737 if(b.size == 'md-left' || b.size == 'md-right'){
30738 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30739 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30742 b.el.setWidth(width);
30743 b.el.setHeight(height);
30745 b.el.select('iframe',true).setSize(width,height);
30749 for (var i = 0; i < this.cols; i++){
30751 if(maxY[i] < maxY[col]){
30756 col = Math.min(col, i);
30760 x = pos.x + col * (this.colWidth + this.padWidth);
30764 var positions = [];
30766 switch (box.length){
30768 positions = this.getVerticalOneBoxColPositions(x, y, box);
30771 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30774 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30777 positions = this.getVerticalFourBoxColPositions(x, y, box);
30783 Roo.each(box, function(b,kk){
30785 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30787 var sz = b.el.getSize();
30789 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30797 for (var i = 0; i < this.cols; i++){
30798 mY = Math.max(mY, maxY[i]);
30801 this.el.setHeight(mY - pos.y);
30805 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30807 // var pos = this.el.getBox(true);
30810 // var maxX = pos.right;
30812 // var maxHeight = 0;
30814 // Roo.each(items, function(item, k){
30818 // item.el.position('absolute');
30820 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30822 // item.el.setWidth(width);
30824 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30826 // item.el.setHeight(height);
30829 // item.el.setXY([x, y], isInstant ? false : true);
30831 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30834 // y = y + height + this.alternativePadWidth;
30836 // maxHeight = maxHeight + height + this.alternativePadWidth;
30840 // this.el.setHeight(maxHeight);
30844 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30846 var pos = this.el.getBox(true);
30851 var maxX = pos.right;
30853 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30855 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30857 Roo.each(queue, function(box, k){
30859 Roo.each(box, function(b, kk){
30861 b.el.position('absolute');
30863 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30864 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30866 if(b.size == 'md-left' || b.size == 'md-right'){
30867 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30868 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30871 b.el.setWidth(width);
30872 b.el.setHeight(height);
30880 var positions = [];
30882 switch (box.length){
30884 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30887 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30890 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30893 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30899 Roo.each(box, function(b,kk){
30901 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30903 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30911 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30913 Roo.each(eItems, function(b,k){
30915 b.size = (k == 0) ? 'sm' : 'xs';
30916 b.x = (k == 0) ? 2 : 1;
30917 b.y = (k == 0) ? 2 : 1;
30919 b.el.position('absolute');
30921 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30923 b.el.setWidth(width);
30925 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30927 b.el.setHeight(height);
30931 var positions = [];
30934 x : maxX - this.unitWidth * 2 - this.gutter,
30939 x : maxX - this.unitWidth,
30940 y : minY + (this.unitWidth + this.gutter) * 2
30944 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30948 Roo.each(eItems, function(b,k){
30950 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30956 getVerticalOneBoxColPositions : function(x, y, box)
30960 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30962 if(box[0].size == 'md-left'){
30966 if(box[0].size == 'md-right'){
30971 x : x + (this.unitWidth + this.gutter) * rand,
30978 getVerticalTwoBoxColPositions : function(x, y, box)
30982 if(box[0].size == 'xs'){
30986 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30990 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31004 x : x + (this.unitWidth + this.gutter) * 2,
31005 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31012 getVerticalThreeBoxColPositions : function(x, y, box)
31016 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31024 x : x + (this.unitWidth + this.gutter) * 1,
31029 x : x + (this.unitWidth + this.gutter) * 2,
31037 if(box[0].size == 'xs' && box[1].size == 'xs'){
31046 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31050 x : x + (this.unitWidth + this.gutter) * 1,
31064 x : x + (this.unitWidth + this.gutter) * 2,
31069 x : x + (this.unitWidth + this.gutter) * 2,
31070 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31077 getVerticalFourBoxColPositions : function(x, y, box)
31081 if(box[0].size == 'xs'){
31090 y : y + (this.unitHeight + this.gutter) * 1
31095 y : y + (this.unitHeight + this.gutter) * 2
31099 x : x + (this.unitWidth + this.gutter) * 1,
31113 x : x + (this.unitWidth + this.gutter) * 2,
31118 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31119 y : y + (this.unitHeight + this.gutter) * 1
31123 x : x + (this.unitWidth + this.gutter) * 2,
31124 y : y + (this.unitWidth + this.gutter) * 2
31131 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31135 if(box[0].size == 'md-left'){
31137 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31144 if(box[0].size == 'md-right'){
31146 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31147 y : minY + (this.unitWidth + this.gutter) * 1
31153 var rand = Math.floor(Math.random() * (4 - box[0].y));
31156 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31157 y : minY + (this.unitWidth + this.gutter) * rand
31164 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31168 if(box[0].size == 'xs'){
31171 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31176 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31177 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31185 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31190 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31191 y : minY + (this.unitWidth + this.gutter) * 2
31198 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31202 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31205 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31210 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31211 y : minY + (this.unitWidth + this.gutter) * 1
31215 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31216 y : minY + (this.unitWidth + this.gutter) * 2
31223 if(box[0].size == 'xs' && box[1].size == 'xs'){
31226 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31231 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31236 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31237 y : minY + (this.unitWidth + this.gutter) * 1
31245 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31250 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31251 y : minY + (this.unitWidth + this.gutter) * 2
31255 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31256 y : minY + (this.unitWidth + this.gutter) * 2
31263 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31267 if(box[0].size == 'xs'){
31270 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31275 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31280 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),
31285 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31286 y : minY + (this.unitWidth + this.gutter) * 1
31294 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31299 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31300 y : minY + (this.unitWidth + this.gutter) * 2
31304 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].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) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31310 y : minY + (this.unitWidth + this.gutter) * 2
31318 * adds a Masonry Brick
31319 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31321 addBrick : function(cfg)
31323 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31324 //this.register(cn);
31325 cn.parentId = this.id;
31326 cn.onRender(this.el, null);
31331 * register a Masonry Brick
31332 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31334 register : function(brick)
31336 this.bricks.push(brick);
31337 brick.masonryId = this.id;
31341 * clear all the Masonry Brick
31343 clearAll : function()
31346 //this.getChildContainer().dom.innerHTML = "";
31347 this.el.dom.innerHTML = '';
31350 getSelected : function()
31352 for (var i=0; i<this.bricks.length; i++) {
31353 Roo.log(this.bricks[i]);
31363 * http://masonry.desandro.com
31365 * The idea is to render all the bricks based on vertical width...
31367 * The original code extends 'outlayer' - we might need to use that....
31373 * @class Roo.bootstrap.LayoutMasonryAuto
31374 * @extends Roo.bootstrap.Component
31375 * Bootstrap Layout Masonry class
31378 * Create a new Element
31379 * @param {Object} config The config object
31382 Roo.bootstrap.LayoutMasonryAuto = function(config){
31383 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31386 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31389 * @cfg {Boolean} isFitWidth - resize the width..
31391 isFitWidth : false, // options..
31393 * @cfg {Boolean} isOriginLeft = left align?
31395 isOriginLeft : true,
31397 * @cfg {Boolean} isOriginTop = top align?
31399 isOriginTop : false,
31401 * @cfg {Boolean} isLayoutInstant = no animation?
31403 isLayoutInstant : false, // needed?
31405 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31407 isResizingContainer : true,
31409 * @cfg {Number} columnWidth width of the columns
31415 * @cfg {Number} maxCols maximum number of columns
31420 * @cfg {Number} padHeight padding below box..
31426 * @cfg {Boolean} isAutoInitial defalut true
31429 isAutoInitial : true,
31435 initialColumnWidth : 0,
31436 currentSize : null,
31438 colYs : null, // array.
31445 bricks: null, //CompositeElement
31446 cols : 0, // array?
31447 // element : null, // wrapped now this.el
31448 _isLayoutInited : null,
31451 getAutoCreate : function(){
31455 cls: 'blog-masonary-wrapper ' + this.cls,
31457 cls : 'mas-boxes masonary'
31464 getChildContainer: function( )
31466 if (this.boxesEl) {
31467 return this.boxesEl;
31470 this.boxesEl = this.el.select('.mas-boxes').first();
31472 return this.boxesEl;
31476 initEvents : function()
31480 if(this.isAutoInitial){
31481 Roo.log('hook children rendered');
31482 this.on('childrenrendered', function() {
31483 Roo.log('children rendered');
31490 initial : function()
31492 this.reloadItems();
31494 this.currentSize = this.el.getBox(true);
31496 /// was window resize... - let's see if this works..
31497 Roo.EventManager.onWindowResize(this.resize, this);
31499 if(!this.isAutoInitial){
31504 this.layout.defer(500,this);
31507 reloadItems: function()
31509 this.bricks = this.el.select('.masonry-brick', true);
31511 this.bricks.each(function(b) {
31512 //Roo.log(b.getSize());
31513 if (!b.attr('originalwidth')) {
31514 b.attr('originalwidth', b.getSize().width);
31519 Roo.log(this.bricks.elements.length);
31522 resize : function()
31525 var cs = this.el.getBox(true);
31527 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31528 Roo.log("no change in with or X");
31531 this.currentSize = cs;
31535 layout : function()
31538 this._resetLayout();
31539 //this._manageStamps();
31541 // don't animate first layout
31542 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31543 this.layoutItems( isInstant );
31545 // flag for initalized
31546 this._isLayoutInited = true;
31549 layoutItems : function( isInstant )
31551 //var items = this._getItemsForLayout( this.items );
31552 // original code supports filtering layout items.. we just ignore it..
31554 this._layoutItems( this.bricks , isInstant );
31556 this._postLayout();
31558 _layoutItems : function ( items , isInstant)
31560 //this.fireEvent( 'layout', this, items );
31563 if ( !items || !items.elements.length ) {
31564 // no items, emit event with empty array
31569 items.each(function(item) {
31570 Roo.log("layout item");
31572 // get x/y object from method
31573 var position = this._getItemLayoutPosition( item );
31575 position.item = item;
31576 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31577 queue.push( position );
31580 this._processLayoutQueue( queue );
31582 /** Sets position of item in DOM
31583 * @param {Element} item
31584 * @param {Number} x - horizontal position
31585 * @param {Number} y - vertical position
31586 * @param {Boolean} isInstant - disables transitions
31588 _processLayoutQueue : function( queue )
31590 for ( var i=0, len = queue.length; i < len; i++ ) {
31591 var obj = queue[i];
31592 obj.item.position('absolute');
31593 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31599 * Any logic you want to do after each layout,
31600 * i.e. size the container
31602 _postLayout : function()
31604 this.resizeContainer();
31607 resizeContainer : function()
31609 if ( !this.isResizingContainer ) {
31612 var size = this._getContainerSize();
31614 this.el.setSize(size.width,size.height);
31615 this.boxesEl.setSize(size.width,size.height);
31621 _resetLayout : function()
31623 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31624 this.colWidth = this.el.getWidth();
31625 //this.gutter = this.el.getWidth();
31627 this.measureColumns();
31633 this.colYs.push( 0 );
31639 measureColumns : function()
31641 this.getContainerWidth();
31642 // if columnWidth is 0, default to outerWidth of first item
31643 if ( !this.columnWidth ) {
31644 var firstItem = this.bricks.first();
31645 Roo.log(firstItem);
31646 this.columnWidth = this.containerWidth;
31647 if (firstItem && firstItem.attr('originalwidth') ) {
31648 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31650 // columnWidth fall back to item of first element
31651 Roo.log("set column width?");
31652 this.initialColumnWidth = this.columnWidth ;
31654 // if first elem has no width, default to size of container
31659 if (this.initialColumnWidth) {
31660 this.columnWidth = this.initialColumnWidth;
31665 // column width is fixed at the top - however if container width get's smaller we should
31668 // this bit calcs how man columns..
31670 var columnWidth = this.columnWidth += this.gutter;
31672 // calculate columns
31673 var containerWidth = this.containerWidth + this.gutter;
31675 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31676 // fix rounding errors, typically with gutters
31677 var excess = columnWidth - containerWidth % columnWidth;
31680 // if overshoot is less than a pixel, round up, otherwise floor it
31681 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31682 cols = Math[ mathMethod ]( cols );
31683 this.cols = Math.max( cols, 1 );
31684 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31686 // padding positioning..
31687 var totalColWidth = this.cols * this.columnWidth;
31688 var padavail = this.containerWidth - totalColWidth;
31689 // so for 2 columns - we need 3 'pads'
31691 var padNeeded = (1+this.cols) * this.padWidth;
31693 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31695 this.columnWidth += padExtra
31696 //this.padWidth = Math.floor(padavail / ( this.cols));
31698 // adjust colum width so that padding is fixed??
31700 // we have 3 columns ... total = width * 3
31701 // we have X left over... that should be used by
31703 //if (this.expandC) {
31711 getContainerWidth : function()
31713 /* // container is parent if fit width
31714 var container = this.isFitWidth ? this.element.parentNode : this.element;
31715 // check that this.size and size are there
31716 // IE8 triggers resize on body size change, so they might not be
31718 var size = getSize( container ); //FIXME
31719 this.containerWidth = size && size.innerWidth; //FIXME
31722 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31726 _getItemLayoutPosition : function( item ) // what is item?
31728 // we resize the item to our columnWidth..
31730 item.setWidth(this.columnWidth);
31731 item.autoBoxAdjust = false;
31733 var sz = item.getSize();
31735 // how many columns does this brick span
31736 var remainder = this.containerWidth % this.columnWidth;
31738 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31739 // round if off by 1 pixel, otherwise use ceil
31740 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31741 colSpan = Math.min( colSpan, this.cols );
31743 // normally this should be '1' as we dont' currently allow multi width columns..
31745 var colGroup = this._getColGroup( colSpan );
31746 // get the minimum Y value from the columns
31747 var minimumY = Math.min.apply( Math, colGroup );
31748 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31750 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31752 // position the brick
31754 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31755 y: this.currentSize.y + minimumY + this.padHeight
31759 // apply setHeight to necessary columns
31760 var setHeight = minimumY + sz.height + this.padHeight;
31761 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31763 var setSpan = this.cols + 1 - colGroup.length;
31764 for ( var i = 0; i < setSpan; i++ ) {
31765 this.colYs[ shortColIndex + i ] = setHeight ;
31772 * @param {Number} colSpan - number of columns the element spans
31773 * @returns {Array} colGroup
31775 _getColGroup : function( colSpan )
31777 if ( colSpan < 2 ) {
31778 // if brick spans only one column, use all the column Ys
31783 // how many different places could this brick fit horizontally
31784 var groupCount = this.cols + 1 - colSpan;
31785 // for each group potential horizontal position
31786 for ( var i = 0; i < groupCount; i++ ) {
31787 // make an array of colY values for that one group
31788 var groupColYs = this.colYs.slice( i, i + colSpan );
31789 // and get the max value of the array
31790 colGroup[i] = Math.max.apply( Math, groupColYs );
31795 _manageStamp : function( stamp )
31797 var stampSize = stamp.getSize();
31798 var offset = stamp.getBox();
31799 // get the columns that this stamp affects
31800 var firstX = this.isOriginLeft ? offset.x : offset.right;
31801 var lastX = firstX + stampSize.width;
31802 var firstCol = Math.floor( firstX / this.columnWidth );
31803 firstCol = Math.max( 0, firstCol );
31805 var lastCol = Math.floor( lastX / this.columnWidth );
31806 // lastCol should not go over if multiple of columnWidth #425
31807 lastCol -= lastX % this.columnWidth ? 0 : 1;
31808 lastCol = Math.min( this.cols - 1, lastCol );
31810 // set colYs to bottom of the stamp
31811 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31814 for ( var i = firstCol; i <= lastCol; i++ ) {
31815 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31820 _getContainerSize : function()
31822 this.maxY = Math.max.apply( Math, this.colYs );
31827 if ( this.isFitWidth ) {
31828 size.width = this._getContainerFitWidth();
31834 _getContainerFitWidth : function()
31836 var unusedCols = 0;
31837 // count unused columns
31840 if ( this.colYs[i] !== 0 ) {
31845 // fit container to columns that have been used
31846 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31849 needsResizeLayout : function()
31851 var previousWidth = this.containerWidth;
31852 this.getContainerWidth();
31853 return previousWidth !== this.containerWidth;
31868 * @class Roo.bootstrap.MasonryBrick
31869 * @extends Roo.bootstrap.Component
31870 * Bootstrap MasonryBrick class
31873 * Create a new MasonryBrick
31874 * @param {Object} config The config object
31877 Roo.bootstrap.MasonryBrick = function(config){
31878 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31884 * When a MasonryBrick is clcik
31885 * @param {Roo.bootstrap.MasonryBrick} this
31886 * @param {Roo.EventObject} e
31892 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31895 * @cfg {String} title
31899 * @cfg {String} html
31903 * @cfg {String} bgimage
31907 * @cfg {String} videourl
31911 * @cfg {String} cls
31915 * @cfg {String} href
31919 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
31924 * @cfg {String} placetitle (center|bottom)
31929 * @cfg {Boolean} isFitContainer defalut true
31931 isFitContainer : true,
31934 * @cfg {Boolean} preventDefault defalut false
31936 preventDefault : false,
31939 * @cfg {Boolean} inverse defalut false
31941 maskInverse : false,
31943 getAutoCreate : function()
31945 if(!this.isFitContainer){
31946 return this.getSplitAutoCreate();
31949 var cls = 'masonry-brick masonry-brick-full';
31951 if(this.href.length){
31952 cls += ' masonry-brick-link';
31955 if(this.bgimage.length){
31956 cls += ' masonry-brick-image';
31959 if(this.maskInverse){
31960 cls += ' mask-inverse';
31963 if(!this.html.length && !this.maskInverse){
31964 cls += ' enable-mask';
31968 cls += ' masonry-' + this.size + '-brick';
31971 if(this.placetitle.length){
31973 switch (this.placetitle) {
31975 cls += ' masonry-center-title';
31978 cls += ' masonry-bottom-title';
31985 if(!this.html.length && !this.bgimage.length){
31986 cls += ' masonry-center-title';
31989 if(!this.html.length && this.bgimage.length){
31990 cls += ' masonry-bottom-title';
31995 cls += ' ' + this.cls;
31999 tag: (this.href.length) ? 'a' : 'div',
32004 cls: 'masonry-brick-paragraph',
32010 if(this.href.length){
32011 cfg.href = this.href;
32014 var cn = cfg.cn[0].cn;
32016 if(this.title.length){
32019 cls: 'masonry-brick-title',
32024 if(this.html.length){
32027 cls: 'masonry-brick-text',
32031 if (!this.title.length && !this.html.length) {
32032 cfg.cn[0].cls += ' hide';
32035 if(this.bgimage.length){
32038 cls: 'masonry-brick-image-view',
32043 if(this.videourl.length){
32044 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32045 // youtube support only?
32048 cls: 'masonry-brick-image-view',
32051 allowfullscreen : true
32059 cls: 'masonry-brick-mask'
32066 getSplitAutoCreate : function()
32068 var cls = 'masonry-brick masonry-brick-split';
32070 if(this.href.length){
32071 cls += ' masonry-brick-link';
32074 if(this.bgimage.length){
32075 cls += ' masonry-brick-image';
32079 cls += ' masonry-' + this.size + '-brick';
32082 switch (this.placetitle) {
32084 cls += ' masonry-center-title';
32087 cls += ' masonry-bottom-title';
32090 if(!this.bgimage.length){
32091 cls += ' masonry-center-title';
32094 if(this.bgimage.length){
32095 cls += ' masonry-bottom-title';
32101 cls += ' ' + this.cls;
32105 tag: (this.href.length) ? 'a' : 'div',
32110 cls: 'masonry-brick-split-head',
32114 cls: 'masonry-brick-paragraph',
32121 cls: 'masonry-brick-split-body',
32127 if(this.href.length){
32128 cfg.href = this.href;
32131 if(this.title.length){
32132 cfg.cn[0].cn[0].cn.push({
32134 cls: 'masonry-brick-title',
32139 if(this.html.length){
32140 cfg.cn[1].cn.push({
32142 cls: 'masonry-brick-text',
32147 if(this.bgimage.length){
32148 cfg.cn[0].cn.push({
32150 cls: 'masonry-brick-image-view',
32155 if(this.videourl.length){
32156 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32157 // youtube support only?
32158 cfg.cn[0].cn.cn.push({
32160 cls: 'masonry-brick-image-view',
32163 allowfullscreen : true
32170 initEvents: function()
32172 switch (this.size) {
32205 this.el.on('touchstart', this.onTouchStart, this);
32206 this.el.on('touchmove', this.onTouchMove, this);
32207 this.el.on('touchend', this.onTouchEnd, this);
32208 this.el.on('contextmenu', this.onContextMenu, this);
32210 this.el.on('mouseenter' ,this.enter, this);
32211 this.el.on('mouseleave', this.leave, this);
32212 this.el.on('click', this.onClick, this);
32215 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32216 this.parent().bricks.push(this);
32221 onClick: function(e, el)
32223 var time = this.endTimer - this.startTimer;
32224 // Roo.log(e.preventDefault());
32227 e.preventDefault();
32232 if(!this.preventDefault){
32236 e.preventDefault();
32238 if (this.activcClass != '') {
32239 this.selectBrick();
32242 this.fireEvent('click', this);
32245 enter: function(e, el)
32247 e.preventDefault();
32249 if(!this.isFitContainer || this.maskInverse){
32253 if(this.bgimage.length && this.html.length){
32254 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32258 leave: function(e, el)
32260 e.preventDefault();
32262 if(!this.isFitContainer || this.maskInverse){
32266 if(this.bgimage.length && this.html.length){
32267 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32271 onTouchStart: function(e, el)
32273 // e.preventDefault();
32275 this.touchmoved = false;
32277 if(!this.isFitContainer){
32281 if(!this.bgimage.length || !this.html.length){
32285 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32287 this.timer = new Date().getTime();
32291 onTouchMove: function(e, el)
32293 this.touchmoved = true;
32296 onContextMenu : function(e,el)
32298 e.preventDefault();
32299 e.stopPropagation();
32303 onTouchEnd: function(e, el)
32305 // e.preventDefault();
32307 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32314 if(!this.bgimage.length || !this.html.length){
32316 if(this.href.length){
32317 window.location.href = this.href;
32323 if(!this.isFitContainer){
32327 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32329 window.location.href = this.href;
32332 selectBrick : function() {
32334 if (!this.parentId) {
32338 Roo.log(this.parentId);
32339 var m = Roo.get(this.parentId);
32340 var index = m.selectedBrick.indexOf(this.id);
32343 this.removeClass(this.activeClass);
32344 m.selectedBrick.splice(index,1);
32345 Roo.log(m.selectedBrick);
32349 this.addClass(this.activeClass);
32350 m.selectedBrick.push(this.id);
32351 Roo.log(m.selectedBrick);
32367 * @class Roo.bootstrap.Brick
32368 * @extends Roo.bootstrap.Component
32369 * Bootstrap Brick class
32372 * Create a new Brick
32373 * @param {Object} config The config object
32376 Roo.bootstrap.Brick = function(config){
32377 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32383 * When a Brick is click
32384 * @param {Roo.bootstrap.Brick} this
32385 * @param {Roo.EventObject} e
32391 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32394 * @cfg {String} title
32398 * @cfg {String} html
32402 * @cfg {String} bgimage
32406 * @cfg {String} cls
32410 * @cfg {String} href
32414 * @cfg {String} video
32418 * @cfg {Boolean} square
32422 getAutoCreate : function()
32424 var cls = 'roo-brick';
32426 if(this.href.length){
32427 cls += ' roo-brick-link';
32430 if(this.bgimage.length){
32431 cls += ' roo-brick-image';
32434 if(!this.html.length && !this.bgimage.length){
32435 cls += ' roo-brick-center-title';
32438 if(!this.html.length && this.bgimage.length){
32439 cls += ' roo-brick-bottom-title';
32443 cls += ' ' + this.cls;
32447 tag: (this.href.length) ? 'a' : 'div',
32452 cls: 'roo-brick-paragraph',
32458 if(this.href.length){
32459 cfg.href = this.href;
32462 var cn = cfg.cn[0].cn;
32464 if(this.title.length){
32467 cls: 'roo-brick-title',
32472 if(this.html.length){
32475 cls: 'roo-brick-text',
32482 if(this.bgimage.length){
32485 cls: 'roo-brick-image-view',
32493 initEvents: function()
32495 if(this.title.length || this.html.length){
32496 this.el.on('mouseenter' ,this.enter, this);
32497 this.el.on('mouseleave', this.leave, this);
32501 Roo.EventManager.onWindowResize(this.resize, this);
32506 resize : function()
32508 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32510 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32512 if(this.bgimage.length){
32513 var image = this.el.select('.roo-brick-image-view', true).first();
32514 image.setWidth(paragraph.getWidth());
32515 image.setHeight(paragraph.getWidth());
32517 this.el.setHeight(paragraph.getWidth());
32523 enter: function(e, el)
32525 e.preventDefault();
32527 if(this.bgimage.length){
32528 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32529 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32533 leave: function(e, el)
32535 e.preventDefault();
32537 if(this.bgimage.length){
32538 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32539 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32555 * @class Roo.bootstrap.NumberField
32556 * @extends Roo.bootstrap.Input
32557 * Bootstrap NumberField class
32563 * Create a new NumberField
32564 * @param {Object} config The config object
32567 Roo.bootstrap.NumberField = function(config){
32568 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32571 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32574 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32576 allowDecimals : true,
32578 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32580 decimalSeparator : ".",
32582 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32584 decimalPrecision : 2,
32586 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32588 allowNegative : true,
32590 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32592 minValue : Number.NEGATIVE_INFINITY,
32594 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32596 maxValue : Number.MAX_VALUE,
32598 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32600 minText : "The minimum value for this field is {0}",
32602 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32604 maxText : "The maximum value for this field is {0}",
32606 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32607 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32609 nanText : "{0} is not a valid number",
32611 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32616 initEvents : function()
32618 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32620 var allowed = "0123456789";
32622 if(this.allowDecimals){
32623 allowed += this.decimalSeparator;
32626 if(this.allowNegative){
32630 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32632 var keyPress = function(e){
32634 var k = e.getKey();
32636 var c = e.getCharCode();
32639 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32640 allowed.indexOf(String.fromCharCode(c)) === -1
32646 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32650 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32655 this.el.on("keypress", keyPress, this);
32658 validateValue : function(value)
32661 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32665 var num = this.parseValue(value);
32668 this.markInvalid(String.format(this.nanText, value));
32672 if(num < this.minValue){
32673 this.markInvalid(String.format(this.minText, this.minValue));
32677 if(num > this.maxValue){
32678 this.markInvalid(String.format(this.maxText, this.maxValue));
32685 getValue : function()
32687 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32690 parseValue : function(value)
32692 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32693 return isNaN(value) ? '' : value;
32696 fixPrecision : function(value)
32698 var nan = isNaN(value);
32700 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32701 return nan ? '' : value;
32703 return parseFloat(value).toFixed(this.decimalPrecision);
32706 setValue : function(v)
32708 v = this.fixPrecision(v);
32709 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32712 decimalPrecisionFcn : function(v)
32714 return Math.floor(v);
32717 beforeBlur : function()
32723 var v = this.parseValue(this.getRawValue());
32738 * @class Roo.bootstrap.DocumentSlider
32739 * @extends Roo.bootstrap.Component
32740 * Bootstrap DocumentSlider class
32743 * Create a new DocumentViewer
32744 * @param {Object} config The config object
32747 Roo.bootstrap.DocumentSlider = function(config){
32748 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32755 * Fire after initEvent
32756 * @param {Roo.bootstrap.DocumentSlider} this
32761 * Fire after update
32762 * @param {Roo.bootstrap.DocumentSlider} this
32768 * @param {Roo.bootstrap.DocumentSlider} this
32774 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32780 getAutoCreate : function()
32784 cls : 'roo-document-slider',
32788 cls : 'roo-document-slider-header',
32792 cls : 'roo-document-slider-header-title'
32798 cls : 'roo-document-slider-body',
32802 cls : 'roo-document-slider-prev',
32806 cls : 'fa fa-chevron-left'
32812 cls : 'roo-document-slider-thumb',
32816 cls : 'roo-document-slider-image'
32822 cls : 'roo-document-slider-next',
32826 cls : 'fa fa-chevron-right'
32838 initEvents : function()
32840 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32841 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32843 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32844 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32846 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32847 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32849 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32850 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32852 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32853 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32855 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32856 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32858 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32859 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32861 this.thumbEl.on('click', this.onClick, this);
32863 this.prevIndicator.on('click', this.prev, this);
32865 this.nextIndicator.on('click', this.next, this);
32869 initial : function()
32871 if(this.files.length){
32872 this.indicator = 1;
32876 this.fireEvent('initial', this);
32879 update : function()
32881 this.imageEl.attr('src', this.files[this.indicator - 1]);
32883 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32885 this.prevIndicator.show();
32887 if(this.indicator == 1){
32888 this.prevIndicator.hide();
32891 this.nextIndicator.show();
32893 if(this.indicator == this.files.length){
32894 this.nextIndicator.hide();
32897 this.thumbEl.scrollTo('top');
32899 this.fireEvent('update', this);
32902 onClick : function(e)
32904 e.preventDefault();
32906 this.fireEvent('click', this);
32911 e.preventDefault();
32913 this.indicator = Math.max(1, this.indicator - 1);
32920 e.preventDefault();
32922 this.indicator = Math.min(this.files.length, this.indicator + 1);
32936 * @class Roo.bootstrap.RadioSet
32937 * @extends Roo.bootstrap.Input
32938 * Bootstrap RadioSet class
32939 * @cfg {String} indicatorpos (left|right) default left
32940 * @cfg {Boolean} inline (true|false) inline the element (default true)
32941 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32943 * Create a new RadioSet
32944 * @param {Object} config The config object
32947 Roo.bootstrap.RadioSet = function(config){
32949 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32953 Roo.bootstrap.RadioSet.register(this);
32958 * Fires when the element is checked or unchecked.
32959 * @param {Roo.bootstrap.RadioSet} this This radio
32960 * @param {Roo.bootstrap.Radio} item The checked item
32967 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32975 indicatorpos : 'left',
32977 getAutoCreate : function()
32981 cls : 'roo-radio-set-label',
32985 html : this.fieldLabel
32990 if(this.indicatorpos == 'left'){
32993 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32994 tooltip : 'This field is required'
32999 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33000 tooltip : 'This field is required'
33006 cls : 'roo-radio-set-items'
33009 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33011 if (align === 'left' && this.fieldLabel.length) {
33014 cls : "roo-radio-set-right",
33020 if(this.labelWidth > 12){
33021 label.style = "width: " + this.labelWidth + 'px';
33024 if(this.labelWidth < 13 && this.labelmd == 0){
33025 this.labelmd = this.labelWidth;
33028 if(this.labellg > 0){
33029 label.cls += ' col-lg-' + this.labellg;
33030 items.cls += ' col-lg-' + (12 - this.labellg);
33033 if(this.labelmd > 0){
33034 label.cls += ' col-md-' + this.labelmd;
33035 items.cls += ' col-md-' + (12 - this.labelmd);
33038 if(this.labelsm > 0){
33039 label.cls += ' col-sm-' + this.labelsm;
33040 items.cls += ' col-sm-' + (12 - this.labelsm);
33043 if(this.labelxs > 0){
33044 label.cls += ' col-xs-' + this.labelxs;
33045 items.cls += ' col-xs-' + (12 - this.labelxs);
33051 cls : 'roo-radio-set',
33055 cls : 'roo-radio-set-input',
33058 value : this.value ? this.value : ''
33065 if(this.weight.length){
33066 cfg.cls += ' roo-radio-' + this.weight;
33070 cfg.cls += ' roo-radio-set-inline';
33077 initEvents : function()
33079 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33080 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33082 if(!this.fieldLabel.length){
33083 this.labelEl.hide();
33086 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33087 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33089 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
33090 this.indicatorEl().hide();
33092 this.originalValue = this.getValue();
33096 inputEl: function ()
33098 return this.el.select('.roo-radio-set-input', true).first();
33101 getChildContainer : function()
33103 return this.itemsEl;
33106 register : function(item)
33108 this.radioes.push(item);
33112 validate : function()
33116 Roo.each(this.radioes, function(i){
33125 if(this.allowBlank) {
33129 if(this.disabled || valid){
33134 this.markInvalid();
33139 markValid : function()
33141 if(this.labelEl.isVisible(true)){
33142 this.indicatorEl().hide();
33145 this.el.removeClass([this.invalidClass, this.validClass]);
33146 this.el.addClass(this.validClass);
33148 this.fireEvent('valid', this);
33151 markInvalid : function(msg)
33153 if(this.allowBlank || this.disabled){
33157 if(this.labelEl.isVisible(true)){
33158 this.indicatorEl().show();
33161 this.el.removeClass([this.invalidClass, this.validClass]);
33162 this.el.addClass(this.invalidClass);
33164 this.fireEvent('invalid', this, msg);
33168 setValue : function(v, suppressEvent)
33170 Roo.each(this.radioes, function(i){
33173 i.el.removeClass('checked');
33175 if(i.value === v || i.value.toString() === v.toString()){
33177 i.el.addClass('checked');
33179 if(suppressEvent !== true){
33180 this.fireEvent('check', this, i);
33186 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
33190 clearInvalid : function(){
33192 if(!this.el || this.preventMark){
33197 if(this.labelEl.isVisible(true)){
33198 this.indicatorEl().hide();
33202 this.el.removeClass([this.invalidClass]);
33204 this.fireEvent('valid', this);
33209 Roo.apply(Roo.bootstrap.RadioSet, {
33213 register : function(set)
33215 this.groups[set.name] = set;
33218 get: function(name)
33220 if (typeof(this.groups[name]) == 'undefined') {
33224 return this.groups[name] ;
33230 * Ext JS Library 1.1.1
33231 * Copyright(c) 2006-2007, Ext JS, LLC.
33233 * Originally Released Under LGPL - original licence link has changed is not relivant.
33236 * <script type="text/javascript">
33241 * @class Roo.bootstrap.SplitBar
33242 * @extends Roo.util.Observable
33243 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33247 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33248 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33249 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33250 split.minSize = 100;
33251 split.maxSize = 600;
33252 split.animate = true;
33253 split.on('moved', splitterMoved);
33256 * Create a new SplitBar
33257 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33258 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33259 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33260 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33261 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33262 position of the SplitBar).
33264 Roo.bootstrap.SplitBar = function(cfg){
33269 // dragElement : elm
33270 // resizingElement: el,
33272 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33273 // placement : Roo.bootstrap.SplitBar.LEFT ,
33274 // existingProxy ???
33277 this.el = Roo.get(cfg.dragElement, true);
33278 this.el.dom.unselectable = "on";
33280 this.resizingEl = Roo.get(cfg.resizingElement, true);
33284 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33285 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33288 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33291 * The minimum size of the resizing element. (Defaults to 0)
33297 * The maximum size of the resizing element. (Defaults to 2000)
33300 this.maxSize = 2000;
33303 * Whether to animate the transition to the new size
33306 this.animate = false;
33309 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33312 this.useShim = false;
33317 if(!cfg.existingProxy){
33319 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33321 this.proxy = Roo.get(cfg.existingProxy).dom;
33324 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33327 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33330 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33333 this.dragSpecs = {};
33336 * @private The adapter to use to positon and resize elements
33338 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33339 this.adapter.init(this);
33341 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33343 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33344 this.el.addClass("roo-splitbar-h");
33347 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33348 this.el.addClass("roo-splitbar-v");
33354 * Fires when the splitter is moved (alias for {@link #event-moved})
33355 * @param {Roo.bootstrap.SplitBar} this
33356 * @param {Number} newSize the new width or height
33361 * Fires when the splitter is moved
33362 * @param {Roo.bootstrap.SplitBar} this
33363 * @param {Number} newSize the new width or height
33367 * @event beforeresize
33368 * Fires before the splitter is dragged
33369 * @param {Roo.bootstrap.SplitBar} this
33371 "beforeresize" : true,
33373 "beforeapply" : true
33376 Roo.util.Observable.call(this);
33379 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33380 onStartProxyDrag : function(x, y){
33381 this.fireEvent("beforeresize", this);
33383 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33385 o.enableDisplayMode("block");
33386 // all splitbars share the same overlay
33387 Roo.bootstrap.SplitBar.prototype.overlay = o;
33389 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33390 this.overlay.show();
33391 Roo.get(this.proxy).setDisplayed("block");
33392 var size = this.adapter.getElementSize(this);
33393 this.activeMinSize = this.getMinimumSize();;
33394 this.activeMaxSize = this.getMaximumSize();;
33395 var c1 = size - this.activeMinSize;
33396 var c2 = Math.max(this.activeMaxSize - size, 0);
33397 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33398 this.dd.resetConstraints();
33399 this.dd.setXConstraint(
33400 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33401 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33403 this.dd.setYConstraint(0, 0);
33405 this.dd.resetConstraints();
33406 this.dd.setXConstraint(0, 0);
33407 this.dd.setYConstraint(
33408 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33409 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33412 this.dragSpecs.startSize = size;
33413 this.dragSpecs.startPoint = [x, y];
33414 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33418 * @private Called after the drag operation by the DDProxy
33420 onEndProxyDrag : function(e){
33421 Roo.get(this.proxy).setDisplayed(false);
33422 var endPoint = Roo.lib.Event.getXY(e);
33424 this.overlay.hide();
33427 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33428 newSize = this.dragSpecs.startSize +
33429 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33430 endPoint[0] - this.dragSpecs.startPoint[0] :
33431 this.dragSpecs.startPoint[0] - endPoint[0]
33434 newSize = this.dragSpecs.startSize +
33435 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33436 endPoint[1] - this.dragSpecs.startPoint[1] :
33437 this.dragSpecs.startPoint[1] - endPoint[1]
33440 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33441 if(newSize != this.dragSpecs.startSize){
33442 if(this.fireEvent('beforeapply', this, newSize) !== false){
33443 this.adapter.setElementSize(this, newSize);
33444 this.fireEvent("moved", this, newSize);
33445 this.fireEvent("resize", this, newSize);
33451 * Get the adapter this SplitBar uses
33452 * @return The adapter object
33454 getAdapter : function(){
33455 return this.adapter;
33459 * Set the adapter this SplitBar uses
33460 * @param {Object} adapter A SplitBar adapter object
33462 setAdapter : function(adapter){
33463 this.adapter = adapter;
33464 this.adapter.init(this);
33468 * Gets the minimum size for the resizing element
33469 * @return {Number} The minimum size
33471 getMinimumSize : function(){
33472 return this.minSize;
33476 * Sets the minimum size for the resizing element
33477 * @param {Number} minSize The minimum size
33479 setMinimumSize : function(minSize){
33480 this.minSize = minSize;
33484 * Gets the maximum size for the resizing element
33485 * @return {Number} The maximum size
33487 getMaximumSize : function(){
33488 return this.maxSize;
33492 * Sets the maximum size for the resizing element
33493 * @param {Number} maxSize The maximum size
33495 setMaximumSize : function(maxSize){
33496 this.maxSize = maxSize;
33500 * Sets the initialize size for the resizing element
33501 * @param {Number} size The initial size
33503 setCurrentSize : function(size){
33504 var oldAnimate = this.animate;
33505 this.animate = false;
33506 this.adapter.setElementSize(this, size);
33507 this.animate = oldAnimate;
33511 * Destroy this splitbar.
33512 * @param {Boolean} removeEl True to remove the element
33514 destroy : function(removeEl){
33516 this.shim.remove();
33519 this.proxy.parentNode.removeChild(this.proxy);
33527 * @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.
33529 Roo.bootstrap.SplitBar.createProxy = function(dir){
33530 var proxy = new Roo.Element(document.createElement("div"));
33531 proxy.unselectable();
33532 var cls = 'roo-splitbar-proxy';
33533 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33534 document.body.appendChild(proxy.dom);
33539 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33540 * Default Adapter. It assumes the splitter and resizing element are not positioned
33541 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33543 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33546 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33547 // do nothing for now
33548 init : function(s){
33552 * Called before drag operations to get the current size of the resizing element.
33553 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33555 getElementSize : function(s){
33556 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33557 return s.resizingEl.getWidth();
33559 return s.resizingEl.getHeight();
33564 * Called after drag operations to set the size of the resizing element.
33565 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33566 * @param {Number} newSize The new size to set
33567 * @param {Function} onComplete A function to be invoked when resizing is complete
33569 setElementSize : function(s, newSize, onComplete){
33570 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33572 s.resizingEl.setWidth(newSize);
33574 onComplete(s, newSize);
33577 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33582 s.resizingEl.setHeight(newSize);
33584 onComplete(s, newSize);
33587 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33594 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33595 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33596 * Adapter that moves the splitter element to align with the resized sizing element.
33597 * Used with an absolute positioned SplitBar.
33598 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33599 * document.body, make sure you assign an id to the body element.
33601 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33602 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33603 this.container = Roo.get(container);
33606 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33607 init : function(s){
33608 this.basic.init(s);
33611 getElementSize : function(s){
33612 return this.basic.getElementSize(s);
33615 setElementSize : function(s, newSize, onComplete){
33616 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33619 moveSplitter : function(s){
33620 var yes = Roo.bootstrap.SplitBar;
33621 switch(s.placement){
33623 s.el.setX(s.resizingEl.getRight());
33626 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33629 s.el.setY(s.resizingEl.getBottom());
33632 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33639 * Orientation constant - Create a vertical SplitBar
33643 Roo.bootstrap.SplitBar.VERTICAL = 1;
33646 * Orientation constant - Create a horizontal SplitBar
33650 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33653 * Placement constant - The resizing element is to the left of the splitter element
33657 Roo.bootstrap.SplitBar.LEFT = 1;
33660 * Placement constant - The resizing element is to the right of the splitter element
33664 Roo.bootstrap.SplitBar.RIGHT = 2;
33667 * Placement constant - The resizing element is positioned above the splitter element
33671 Roo.bootstrap.SplitBar.TOP = 3;
33674 * Placement constant - The resizing element is positioned under splitter element
33678 Roo.bootstrap.SplitBar.BOTTOM = 4;
33679 Roo.namespace("Roo.bootstrap.layout");/*
33681 * Ext JS Library 1.1.1
33682 * Copyright(c) 2006-2007, Ext JS, LLC.
33684 * Originally Released Under LGPL - original licence link has changed is not relivant.
33687 * <script type="text/javascript">
33691 * @class Roo.bootstrap.layout.Manager
33692 * @extends Roo.bootstrap.Component
33693 * Base class for layout managers.
33695 Roo.bootstrap.layout.Manager = function(config)
33697 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33703 /** false to disable window resize monitoring @type Boolean */
33704 this.monitorWindowResize = true;
33709 * Fires when a layout is performed.
33710 * @param {Roo.LayoutManager} this
33714 * @event regionresized
33715 * Fires when the user resizes a region.
33716 * @param {Roo.LayoutRegion} region The resized region
33717 * @param {Number} newSize The new size (width for east/west, height for north/south)
33719 "regionresized" : true,
33721 * @event regioncollapsed
33722 * Fires when a region is collapsed.
33723 * @param {Roo.LayoutRegion} region The collapsed region
33725 "regioncollapsed" : true,
33727 * @event regionexpanded
33728 * Fires when a region is expanded.
33729 * @param {Roo.LayoutRegion} region The expanded region
33731 "regionexpanded" : true
33733 this.updating = false;
33736 this.el = Roo.get(config.el);
33742 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33747 monitorWindowResize : true,
33753 onRender : function(ct, position)
33756 this.el = Roo.get(ct);
33759 //this.fireEvent('render',this);
33763 initEvents: function()
33767 // ie scrollbar fix
33768 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33769 document.body.scroll = "no";
33770 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33771 this.el.position('relative');
33773 this.id = this.el.id;
33774 this.el.addClass("roo-layout-container");
33775 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33776 if(this.el.dom != document.body ) {
33777 this.el.on('resize', this.layout,this);
33778 this.el.on('show', this.layout,this);
33784 * Returns true if this layout is currently being updated
33785 * @return {Boolean}
33787 isUpdating : function(){
33788 return this.updating;
33792 * Suspend the LayoutManager from doing auto-layouts while
33793 * making multiple add or remove calls
33795 beginUpdate : function(){
33796 this.updating = true;
33800 * Restore auto-layouts and optionally disable the manager from performing a layout
33801 * @param {Boolean} noLayout true to disable a layout update
33803 endUpdate : function(noLayout){
33804 this.updating = false;
33810 layout: function(){
33814 onRegionResized : function(region, newSize){
33815 this.fireEvent("regionresized", region, newSize);
33819 onRegionCollapsed : function(region){
33820 this.fireEvent("regioncollapsed", region);
33823 onRegionExpanded : function(region){
33824 this.fireEvent("regionexpanded", region);
33828 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33829 * performs box-model adjustments.
33830 * @return {Object} The size as an object {width: (the width), height: (the height)}
33832 getViewSize : function()
33835 if(this.el.dom != document.body){
33836 size = this.el.getSize();
33838 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33840 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33841 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33846 * Returns the Element this layout is bound to.
33847 * @return {Roo.Element}
33849 getEl : function(){
33854 * Returns the specified region.
33855 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33856 * @return {Roo.LayoutRegion}
33858 getRegion : function(target){
33859 return this.regions[target.toLowerCase()];
33862 onWindowResize : function(){
33863 if(this.monitorWindowResize){
33870 * Ext JS Library 1.1.1
33871 * Copyright(c) 2006-2007, Ext JS, LLC.
33873 * Originally Released Under LGPL - original licence link has changed is not relivant.
33876 * <script type="text/javascript">
33879 * @class Roo.bootstrap.layout.Border
33880 * @extends Roo.bootstrap.layout.Manager
33881 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33882 * please see: examples/bootstrap/nested.html<br><br>
33884 <b>The container the layout is rendered into can be either the body element or any other element.
33885 If it is not the body element, the container needs to either be an absolute positioned element,
33886 or you will need to add "position:relative" to the css of the container. You will also need to specify
33887 the container size if it is not the body element.</b>
33890 * Create a new Border
33891 * @param {Object} config Configuration options
33893 Roo.bootstrap.layout.Border = function(config){
33894 config = config || {};
33895 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33899 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33900 if(config[region]){
33901 config[region].region = region;
33902 this.addRegion(config[region]);
33908 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33910 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33912 * Creates and adds a new region if it doesn't already exist.
33913 * @param {String} target The target region key (north, south, east, west or center).
33914 * @param {Object} config The regions config object
33915 * @return {BorderLayoutRegion} The new region
33917 addRegion : function(config)
33919 if(!this.regions[config.region]){
33920 var r = this.factory(config);
33921 this.bindRegion(r);
33923 return this.regions[config.region];
33927 bindRegion : function(r){
33928 this.regions[r.config.region] = r;
33930 r.on("visibilitychange", this.layout, this);
33931 r.on("paneladded", this.layout, this);
33932 r.on("panelremoved", this.layout, this);
33933 r.on("invalidated", this.layout, this);
33934 r.on("resized", this.onRegionResized, this);
33935 r.on("collapsed", this.onRegionCollapsed, this);
33936 r.on("expanded", this.onRegionExpanded, this);
33940 * Performs a layout update.
33942 layout : function()
33944 if(this.updating) {
33948 // render all the rebions if they have not been done alreayd?
33949 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33950 if(this.regions[region] && !this.regions[region].bodyEl){
33951 this.regions[region].onRender(this.el)
33955 var size = this.getViewSize();
33956 var w = size.width;
33957 var h = size.height;
33962 //var x = 0, y = 0;
33964 var rs = this.regions;
33965 var north = rs["north"];
33966 var south = rs["south"];
33967 var west = rs["west"];
33968 var east = rs["east"];
33969 var center = rs["center"];
33970 //if(this.hideOnLayout){ // not supported anymore
33971 //c.el.setStyle("display", "none");
33973 if(north && north.isVisible()){
33974 var b = north.getBox();
33975 var m = north.getMargins();
33976 b.width = w - (m.left+m.right);
33979 centerY = b.height + b.y + m.bottom;
33980 centerH -= centerY;
33981 north.updateBox(this.safeBox(b));
33983 if(south && south.isVisible()){
33984 var b = south.getBox();
33985 var m = south.getMargins();
33986 b.width = w - (m.left+m.right);
33988 var totalHeight = (b.height + m.top + m.bottom);
33989 b.y = h - totalHeight + m.top;
33990 centerH -= totalHeight;
33991 south.updateBox(this.safeBox(b));
33993 if(west && west.isVisible()){
33994 var b = west.getBox();
33995 var m = west.getMargins();
33996 b.height = centerH - (m.top+m.bottom);
33998 b.y = centerY + m.top;
33999 var totalWidth = (b.width + m.left + m.right);
34000 centerX += totalWidth;
34001 centerW -= totalWidth;
34002 west.updateBox(this.safeBox(b));
34004 if(east && east.isVisible()){
34005 var b = east.getBox();
34006 var m = east.getMargins();
34007 b.height = centerH - (m.top+m.bottom);
34008 var totalWidth = (b.width + m.left + m.right);
34009 b.x = w - totalWidth + m.left;
34010 b.y = centerY + m.top;
34011 centerW -= totalWidth;
34012 east.updateBox(this.safeBox(b));
34015 var m = center.getMargins();
34017 x: centerX + m.left,
34018 y: centerY + m.top,
34019 width: centerW - (m.left+m.right),
34020 height: centerH - (m.top+m.bottom)
34022 //if(this.hideOnLayout){
34023 //center.el.setStyle("display", "block");
34025 center.updateBox(this.safeBox(centerBox));
34028 this.fireEvent("layout", this);
34032 safeBox : function(box){
34033 box.width = Math.max(0, box.width);
34034 box.height = Math.max(0, box.height);
34039 * Adds a ContentPanel (or subclass) to this layout.
34040 * @param {String} target The target region key (north, south, east, west or center).
34041 * @param {Roo.ContentPanel} panel The panel to add
34042 * @return {Roo.ContentPanel} The added panel
34044 add : function(target, panel){
34046 target = target.toLowerCase();
34047 return this.regions[target].add(panel);
34051 * Remove a ContentPanel (or subclass) to this layout.
34052 * @param {String} target The target region key (north, south, east, west or center).
34053 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34054 * @return {Roo.ContentPanel} The removed panel
34056 remove : function(target, panel){
34057 target = target.toLowerCase();
34058 return this.regions[target].remove(panel);
34062 * Searches all regions for a panel with the specified id
34063 * @param {String} panelId
34064 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34066 findPanel : function(panelId){
34067 var rs = this.regions;
34068 for(var target in rs){
34069 if(typeof rs[target] != "function"){
34070 var p = rs[target].getPanel(panelId);
34080 * Searches all regions for a panel with the specified id and activates (shows) it.
34081 * @param {String/ContentPanel} panelId The panels id or the panel itself
34082 * @return {Roo.ContentPanel} The shown panel or null
34084 showPanel : function(panelId) {
34085 var rs = this.regions;
34086 for(var target in rs){
34087 var r = rs[target];
34088 if(typeof r != "function"){
34089 if(r.hasPanel(panelId)){
34090 return r.showPanel(panelId);
34098 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34099 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34102 restoreState : function(provider){
34104 provider = Roo.state.Manager;
34106 var sm = new Roo.LayoutStateManager();
34107 sm.init(this, provider);
34113 * Adds a xtype elements to the layout.
34117 xtype : 'ContentPanel',
34124 xtype : 'NestedLayoutPanel',
34130 items : [ ... list of content panels or nested layout panels.. ]
34134 * @param {Object} cfg Xtype definition of item to add.
34136 addxtype : function(cfg)
34138 // basically accepts a pannel...
34139 // can accept a layout region..!?!?
34140 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34143 // theory? children can only be panels??
34145 //if (!cfg.xtype.match(/Panel$/)) {
34150 if (typeof(cfg.region) == 'undefined') {
34151 Roo.log("Failed to add Panel, region was not set");
34155 var region = cfg.region;
34161 xitems = cfg.items;
34168 case 'Content': // ContentPanel (el, cfg)
34169 case 'Scroll': // ContentPanel (el, cfg)
34171 cfg.autoCreate = true;
34172 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34174 // var el = this.el.createChild();
34175 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34178 this.add(region, ret);
34182 case 'TreePanel': // our new panel!
34183 cfg.el = this.el.createChild();
34184 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34185 this.add(region, ret);
34190 // create a new Layout (which is a Border Layout...
34192 var clayout = cfg.layout;
34193 clayout.el = this.el.createChild();
34194 clayout.items = clayout.items || [];
34198 // replace this exitems with the clayout ones..
34199 xitems = clayout.items;
34201 // force background off if it's in center...
34202 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34203 cfg.background = false;
34205 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34208 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34209 //console.log('adding nested layout panel ' + cfg.toSource());
34210 this.add(region, ret);
34211 nb = {}; /// find first...
34216 // needs grid and region
34218 //var el = this.getRegion(region).el.createChild();
34220 *var el = this.el.createChild();
34221 // create the grid first...
34222 cfg.grid.container = el;
34223 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34226 if (region == 'center' && this.active ) {
34227 cfg.background = false;
34230 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34232 this.add(region, ret);
34234 if (cfg.background) {
34235 // render grid on panel activation (if panel background)
34236 ret.on('activate', function(gp) {
34237 if (!gp.grid.rendered) {
34238 // gp.grid.render(el);
34242 // cfg.grid.render(el);
34248 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34249 // it was the old xcomponent building that caused this before.
34250 // espeically if border is the top element in the tree.
34260 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34262 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34263 this.add(region, ret);
34267 throw "Can not add '" + cfg.xtype + "' to Border";
34273 this.beginUpdate();
34277 Roo.each(xitems, function(i) {
34278 region = nb && i.region ? i.region : false;
34280 var add = ret.addxtype(i);
34283 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34284 if (!i.background) {
34285 abn[region] = nb[region] ;
34292 // make the last non-background panel active..
34293 //if (nb) { Roo.log(abn); }
34296 for(var r in abn) {
34297 region = this.getRegion(r);
34299 // tried using nb[r], but it does not work..
34301 region.showPanel(abn[r]);
34312 factory : function(cfg)
34315 var validRegions = Roo.bootstrap.layout.Border.regions;
34317 var target = cfg.region;
34320 var r = Roo.bootstrap.layout;
34324 return new r.North(cfg);
34326 return new r.South(cfg);
34328 return new r.East(cfg);
34330 return new r.West(cfg);
34332 return new r.Center(cfg);
34334 throw 'Layout region "'+target+'" not supported.';
34341 * Ext JS Library 1.1.1
34342 * Copyright(c) 2006-2007, Ext JS, LLC.
34344 * Originally Released Under LGPL - original licence link has changed is not relivant.
34347 * <script type="text/javascript">
34351 * @class Roo.bootstrap.layout.Basic
34352 * @extends Roo.util.Observable
34353 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34354 * and does not have a titlebar, tabs or any other features. All it does is size and position
34355 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34356 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34357 * @cfg {string} region the region that it inhabits..
34358 * @cfg {bool} skipConfig skip config?
34362 Roo.bootstrap.layout.Basic = function(config){
34364 this.mgr = config.mgr;
34366 this.position = config.region;
34368 var skipConfig = config.skipConfig;
34372 * @scope Roo.BasicLayoutRegion
34376 * @event beforeremove
34377 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34378 * @param {Roo.LayoutRegion} this
34379 * @param {Roo.ContentPanel} panel The panel
34380 * @param {Object} e The cancel event object
34382 "beforeremove" : true,
34384 * @event invalidated
34385 * Fires when the layout for this region is changed.
34386 * @param {Roo.LayoutRegion} this
34388 "invalidated" : true,
34390 * @event visibilitychange
34391 * Fires when this region is shown or hidden
34392 * @param {Roo.LayoutRegion} this
34393 * @param {Boolean} visibility true or false
34395 "visibilitychange" : true,
34397 * @event paneladded
34398 * Fires when a panel is added.
34399 * @param {Roo.LayoutRegion} this
34400 * @param {Roo.ContentPanel} panel The panel
34402 "paneladded" : true,
34404 * @event panelremoved
34405 * Fires when a panel is removed.
34406 * @param {Roo.LayoutRegion} this
34407 * @param {Roo.ContentPanel} panel The panel
34409 "panelremoved" : true,
34411 * @event beforecollapse
34412 * Fires when this region before collapse.
34413 * @param {Roo.LayoutRegion} this
34415 "beforecollapse" : true,
34418 * Fires when this region is collapsed.
34419 * @param {Roo.LayoutRegion} this
34421 "collapsed" : true,
34424 * Fires when this region is expanded.
34425 * @param {Roo.LayoutRegion} this
34430 * Fires when this region is slid into view.
34431 * @param {Roo.LayoutRegion} this
34433 "slideshow" : true,
34436 * Fires when this region slides out of view.
34437 * @param {Roo.LayoutRegion} this
34439 "slidehide" : true,
34441 * @event panelactivated
34442 * Fires when a panel is activated.
34443 * @param {Roo.LayoutRegion} this
34444 * @param {Roo.ContentPanel} panel The activated panel
34446 "panelactivated" : true,
34449 * Fires when the user resizes this region.
34450 * @param {Roo.LayoutRegion} this
34451 * @param {Number} newSize The new size (width for east/west, height for north/south)
34455 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34456 this.panels = new Roo.util.MixedCollection();
34457 this.panels.getKey = this.getPanelId.createDelegate(this);
34459 this.activePanel = null;
34460 // ensure listeners are added...
34462 if (config.listeners || config.events) {
34463 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34464 listeners : config.listeners || {},
34465 events : config.events || {}
34469 if(skipConfig !== true){
34470 this.applyConfig(config);
34474 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34476 getPanelId : function(p){
34480 applyConfig : function(config){
34481 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34482 this.config = config;
34487 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34488 * the width, for horizontal (north, south) the height.
34489 * @param {Number} newSize The new width or height
34491 resizeTo : function(newSize){
34492 var el = this.el ? this.el :
34493 (this.activePanel ? this.activePanel.getEl() : null);
34495 switch(this.position){
34498 el.setWidth(newSize);
34499 this.fireEvent("resized", this, newSize);
34503 el.setHeight(newSize);
34504 this.fireEvent("resized", this, newSize);
34510 getBox : function(){
34511 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34514 getMargins : function(){
34515 return this.margins;
34518 updateBox : function(box){
34520 var el = this.activePanel.getEl();
34521 el.dom.style.left = box.x + "px";
34522 el.dom.style.top = box.y + "px";
34523 this.activePanel.setSize(box.width, box.height);
34527 * Returns the container element for this region.
34528 * @return {Roo.Element}
34530 getEl : function(){
34531 return this.activePanel;
34535 * Returns true if this region is currently visible.
34536 * @return {Boolean}
34538 isVisible : function(){
34539 return this.activePanel ? true : false;
34542 setActivePanel : function(panel){
34543 panel = this.getPanel(panel);
34544 if(this.activePanel && this.activePanel != panel){
34545 this.activePanel.setActiveState(false);
34546 this.activePanel.getEl().setLeftTop(-10000,-10000);
34548 this.activePanel = panel;
34549 panel.setActiveState(true);
34551 panel.setSize(this.box.width, this.box.height);
34553 this.fireEvent("panelactivated", this, panel);
34554 this.fireEvent("invalidated");
34558 * Show the specified panel.
34559 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34560 * @return {Roo.ContentPanel} The shown panel or null
34562 showPanel : function(panel){
34563 panel = this.getPanel(panel);
34565 this.setActivePanel(panel);
34571 * Get the active panel for this region.
34572 * @return {Roo.ContentPanel} The active panel or null
34574 getActivePanel : function(){
34575 return this.activePanel;
34579 * Add the passed ContentPanel(s)
34580 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34581 * @return {Roo.ContentPanel} The panel added (if only one was added)
34583 add : function(panel){
34584 if(arguments.length > 1){
34585 for(var i = 0, len = arguments.length; i < len; i++) {
34586 this.add(arguments[i]);
34590 if(this.hasPanel(panel)){
34591 this.showPanel(panel);
34594 var el = panel.getEl();
34595 if(el.dom.parentNode != this.mgr.el.dom){
34596 this.mgr.el.dom.appendChild(el.dom);
34598 if(panel.setRegion){
34599 panel.setRegion(this);
34601 this.panels.add(panel);
34602 el.setStyle("position", "absolute");
34603 if(!panel.background){
34604 this.setActivePanel(panel);
34605 if(this.config.initialSize && this.panels.getCount()==1){
34606 this.resizeTo(this.config.initialSize);
34609 this.fireEvent("paneladded", this, panel);
34614 * Returns true if the panel is in this region.
34615 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34616 * @return {Boolean}
34618 hasPanel : function(panel){
34619 if(typeof panel == "object"){ // must be panel obj
34620 panel = panel.getId();
34622 return this.getPanel(panel) ? true : false;
34626 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34627 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34628 * @param {Boolean} preservePanel Overrides the config preservePanel option
34629 * @return {Roo.ContentPanel} The panel that was removed
34631 remove : function(panel, preservePanel){
34632 panel = this.getPanel(panel);
34637 this.fireEvent("beforeremove", this, panel, e);
34638 if(e.cancel === true){
34641 var panelId = panel.getId();
34642 this.panels.removeKey(panelId);
34647 * Returns the panel specified or null if it's not in this region.
34648 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34649 * @return {Roo.ContentPanel}
34651 getPanel : function(id){
34652 if(typeof id == "object"){ // must be panel obj
34655 return this.panels.get(id);
34659 * Returns this regions position (north/south/east/west/center).
34662 getPosition: function(){
34663 return this.position;
34667 * Ext JS Library 1.1.1
34668 * Copyright(c) 2006-2007, Ext JS, LLC.
34670 * Originally Released Under LGPL - original licence link has changed is not relivant.
34673 * <script type="text/javascript">
34677 * @class Roo.bootstrap.layout.Region
34678 * @extends Roo.bootstrap.layout.Basic
34679 * This class represents a region in a layout manager.
34681 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34682 * @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})
34683 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34684 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34685 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34686 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34687 * @cfg {String} title The title for the region (overrides panel titles)
34688 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34689 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34690 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34691 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34692 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34693 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34694 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34695 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34696 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34697 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34699 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34700 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34701 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34702 * @cfg {Number} width For East/West panels
34703 * @cfg {Number} height For North/South panels
34704 * @cfg {Boolean} split To show the splitter
34705 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34707 * @cfg {string} cls Extra CSS classes to add to region
34709 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34710 * @cfg {string} region the region that it inhabits..
34713 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34714 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34716 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34717 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34718 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34720 Roo.bootstrap.layout.Region = function(config)
34722 this.applyConfig(config);
34724 var mgr = config.mgr;
34725 var pos = config.region;
34726 config.skipConfig = true;
34727 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34730 this.onRender(mgr.el);
34733 this.visible = true;
34734 this.collapsed = false;
34735 this.unrendered_panels = [];
34738 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34740 position: '', // set by wrapper (eg. north/south etc..)
34741 unrendered_panels : null, // unrendered panels.
34742 createBody : function(){
34743 /** This region's body element
34744 * @type Roo.Element */
34745 this.bodyEl = this.el.createChild({
34747 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34751 onRender: function(ctr, pos)
34753 var dh = Roo.DomHelper;
34754 /** This region's container element
34755 * @type Roo.Element */
34756 this.el = dh.append(ctr.dom, {
34758 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34760 /** This region's title element
34761 * @type Roo.Element */
34763 this.titleEl = dh.append(this.el.dom,
34766 unselectable: "on",
34767 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34769 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34770 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34773 this.titleEl.enableDisplayMode();
34774 /** This region's title text element
34775 * @type HTMLElement */
34776 this.titleTextEl = this.titleEl.dom.firstChild;
34777 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34779 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34780 this.closeBtn.enableDisplayMode();
34781 this.closeBtn.on("click", this.closeClicked, this);
34782 this.closeBtn.hide();
34784 this.createBody(this.config);
34785 if(this.config.hideWhenEmpty){
34787 this.on("paneladded", this.validateVisibility, this);
34788 this.on("panelremoved", this.validateVisibility, this);
34790 if(this.autoScroll){
34791 this.bodyEl.setStyle("overflow", "auto");
34793 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34795 //if(c.titlebar !== false){
34796 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34797 this.titleEl.hide();
34799 this.titleEl.show();
34800 if(this.config.title){
34801 this.titleTextEl.innerHTML = this.config.title;
34805 if(this.config.collapsed){
34806 this.collapse(true);
34808 if(this.config.hidden){
34812 if (this.unrendered_panels && this.unrendered_panels.length) {
34813 for (var i =0;i< this.unrendered_panels.length; i++) {
34814 this.add(this.unrendered_panels[i]);
34816 this.unrendered_panels = null;
34822 applyConfig : function(c)
34825 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34826 var dh = Roo.DomHelper;
34827 if(c.titlebar !== false){
34828 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34829 this.collapseBtn.on("click", this.collapse, this);
34830 this.collapseBtn.enableDisplayMode();
34832 if(c.showPin === true || this.showPin){
34833 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34834 this.stickBtn.enableDisplayMode();
34835 this.stickBtn.on("click", this.expand, this);
34836 this.stickBtn.hide();
34841 /** This region's collapsed element
34842 * @type Roo.Element */
34845 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34846 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34849 if(c.floatable !== false){
34850 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34851 this.collapsedEl.on("click", this.collapseClick, this);
34854 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34855 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34856 id: "message", unselectable: "on", style:{"float":"left"}});
34857 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34859 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34860 this.expandBtn.on("click", this.expand, this);
34864 if(this.collapseBtn){
34865 this.collapseBtn.setVisible(c.collapsible == true);
34868 this.cmargins = c.cmargins || this.cmargins ||
34869 (this.position == "west" || this.position == "east" ?
34870 {top: 0, left: 2, right:2, bottom: 0} :
34871 {top: 2, left: 0, right:0, bottom: 2});
34873 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34876 this.bottomTabs = c.tabPosition != "top";
34878 this.autoScroll = c.autoScroll || false;
34883 this.duration = c.duration || .30;
34884 this.slideDuration = c.slideDuration || .45;
34889 * Returns true if this region is currently visible.
34890 * @return {Boolean}
34892 isVisible : function(){
34893 return this.visible;
34897 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34898 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34900 //setCollapsedTitle : function(title){
34901 // title = title || " ";
34902 // if(this.collapsedTitleTextEl){
34903 // this.collapsedTitleTextEl.innerHTML = title;
34907 getBox : function(){
34909 // if(!this.collapsed){
34910 b = this.el.getBox(false, true);
34912 // b = this.collapsedEl.getBox(false, true);
34917 getMargins : function(){
34918 return this.margins;
34919 //return this.collapsed ? this.cmargins : this.margins;
34922 highlight : function(){
34923 this.el.addClass("x-layout-panel-dragover");
34926 unhighlight : function(){
34927 this.el.removeClass("x-layout-panel-dragover");
34930 updateBox : function(box)
34932 if (!this.bodyEl) {
34933 return; // not rendered yet..
34937 if(!this.collapsed){
34938 this.el.dom.style.left = box.x + "px";
34939 this.el.dom.style.top = box.y + "px";
34940 this.updateBody(box.width, box.height);
34942 this.collapsedEl.dom.style.left = box.x + "px";
34943 this.collapsedEl.dom.style.top = box.y + "px";
34944 this.collapsedEl.setSize(box.width, box.height);
34947 this.tabs.autoSizeTabs();
34951 updateBody : function(w, h)
34954 this.el.setWidth(w);
34955 w -= this.el.getBorderWidth("rl");
34956 if(this.config.adjustments){
34957 w += this.config.adjustments[0];
34960 if(h !== null && h > 0){
34961 this.el.setHeight(h);
34962 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34963 h -= this.el.getBorderWidth("tb");
34964 if(this.config.adjustments){
34965 h += this.config.adjustments[1];
34967 this.bodyEl.setHeight(h);
34969 h = this.tabs.syncHeight(h);
34972 if(this.panelSize){
34973 w = w !== null ? w : this.panelSize.width;
34974 h = h !== null ? h : this.panelSize.height;
34976 if(this.activePanel){
34977 var el = this.activePanel.getEl();
34978 w = w !== null ? w : el.getWidth();
34979 h = h !== null ? h : el.getHeight();
34980 this.panelSize = {width: w, height: h};
34981 this.activePanel.setSize(w, h);
34983 if(Roo.isIE && this.tabs){
34984 this.tabs.el.repaint();
34989 * Returns the container element for this region.
34990 * @return {Roo.Element}
34992 getEl : function(){
34997 * Hides this region.
35000 //if(!this.collapsed){
35001 this.el.dom.style.left = "-2000px";
35004 // this.collapsedEl.dom.style.left = "-2000px";
35005 // this.collapsedEl.hide();
35007 this.visible = false;
35008 this.fireEvent("visibilitychange", this, false);
35012 * Shows this region if it was previously hidden.
35015 //if(!this.collapsed){
35018 // this.collapsedEl.show();
35020 this.visible = true;
35021 this.fireEvent("visibilitychange", this, true);
35024 closeClicked : function(){
35025 if(this.activePanel){
35026 this.remove(this.activePanel);
35030 collapseClick : function(e){
35032 e.stopPropagation();
35035 e.stopPropagation();
35041 * Collapses this region.
35042 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35045 collapse : function(skipAnim, skipCheck = false){
35046 if(this.collapsed) {
35050 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35052 this.collapsed = true;
35054 this.split.el.hide();
35056 if(this.config.animate && skipAnim !== true){
35057 this.fireEvent("invalidated", this);
35058 this.animateCollapse();
35060 this.el.setLocation(-20000,-20000);
35062 this.collapsedEl.show();
35063 this.fireEvent("collapsed", this);
35064 this.fireEvent("invalidated", this);
35070 animateCollapse : function(){
35075 * Expands this region if it was previously collapsed.
35076 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35077 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35080 expand : function(e, skipAnim){
35082 e.stopPropagation();
35084 if(!this.collapsed || this.el.hasActiveFx()) {
35088 this.afterSlideIn();
35091 this.collapsed = false;
35092 if(this.config.animate && skipAnim !== true){
35093 this.animateExpand();
35097 this.split.el.show();
35099 this.collapsedEl.setLocation(-2000,-2000);
35100 this.collapsedEl.hide();
35101 this.fireEvent("invalidated", this);
35102 this.fireEvent("expanded", this);
35106 animateExpand : function(){
35110 initTabs : function()
35112 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35114 var ts = new Roo.bootstrap.panel.Tabs({
35115 el: this.bodyEl.dom,
35116 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35117 disableTooltips: this.config.disableTabTips,
35118 toolbar : this.config.toolbar
35121 if(this.config.hideTabs){
35122 ts.stripWrap.setDisplayed(false);
35125 ts.resizeTabs = this.config.resizeTabs === true;
35126 ts.minTabWidth = this.config.minTabWidth || 40;
35127 ts.maxTabWidth = this.config.maxTabWidth || 250;
35128 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35129 ts.monitorResize = false;
35130 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35131 ts.bodyEl.addClass('roo-layout-tabs-body');
35132 this.panels.each(this.initPanelAsTab, this);
35135 initPanelAsTab : function(panel){
35136 var ti = this.tabs.addTab(
35140 this.config.closeOnTab && panel.isClosable(),
35143 if(panel.tabTip !== undefined){
35144 ti.setTooltip(panel.tabTip);
35146 ti.on("activate", function(){
35147 this.setActivePanel(panel);
35150 if(this.config.closeOnTab){
35151 ti.on("beforeclose", function(t, e){
35153 this.remove(panel);
35157 panel.tabItem = ti;
35162 updatePanelTitle : function(panel, title)
35164 if(this.activePanel == panel){
35165 this.updateTitle(title);
35168 var ti = this.tabs.getTab(panel.getEl().id);
35170 if(panel.tabTip !== undefined){
35171 ti.setTooltip(panel.tabTip);
35176 updateTitle : function(title){
35177 if(this.titleTextEl && !this.config.title){
35178 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35182 setActivePanel : function(panel)
35184 panel = this.getPanel(panel);
35185 if(this.activePanel && this.activePanel != panel){
35186 this.activePanel.setActiveState(false);
35188 this.activePanel = panel;
35189 panel.setActiveState(true);
35190 if(this.panelSize){
35191 panel.setSize(this.panelSize.width, this.panelSize.height);
35194 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35196 this.updateTitle(panel.getTitle());
35198 this.fireEvent("invalidated", this);
35200 this.fireEvent("panelactivated", this, panel);
35204 * Shows the specified panel.
35205 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35206 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35208 showPanel : function(panel)
35210 panel = this.getPanel(panel);
35213 var tab = this.tabs.getTab(panel.getEl().id);
35214 if(tab.isHidden()){
35215 this.tabs.unhideTab(tab.id);
35219 this.setActivePanel(panel);
35226 * Get the active panel for this region.
35227 * @return {Roo.ContentPanel} The active panel or null
35229 getActivePanel : function(){
35230 return this.activePanel;
35233 validateVisibility : function(){
35234 if(this.panels.getCount() < 1){
35235 this.updateTitle(" ");
35236 this.closeBtn.hide();
35239 if(!this.isVisible()){
35246 * Adds the passed ContentPanel(s) to this region.
35247 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35248 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35250 add : function(panel)
35252 if(arguments.length > 1){
35253 for(var i = 0, len = arguments.length; i < len; i++) {
35254 this.add(arguments[i]);
35259 // if we have not been rendered yet, then we can not really do much of this..
35260 if (!this.bodyEl) {
35261 this.unrendered_panels.push(panel);
35268 if(this.hasPanel(panel)){
35269 this.showPanel(panel);
35272 panel.setRegion(this);
35273 this.panels.add(panel);
35274 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35275 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35276 // and hide them... ???
35277 this.bodyEl.dom.appendChild(panel.getEl().dom);
35278 if(panel.background !== true){
35279 this.setActivePanel(panel);
35281 this.fireEvent("paneladded", this, panel);
35288 this.initPanelAsTab(panel);
35292 if(panel.background !== true){
35293 this.tabs.activate(panel.getEl().id);
35295 this.fireEvent("paneladded", this, panel);
35300 * Hides the tab for the specified panel.
35301 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35303 hidePanel : function(panel){
35304 if(this.tabs && (panel = this.getPanel(panel))){
35305 this.tabs.hideTab(panel.getEl().id);
35310 * Unhides the tab for a previously hidden panel.
35311 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35313 unhidePanel : function(panel){
35314 if(this.tabs && (panel = this.getPanel(panel))){
35315 this.tabs.unhideTab(panel.getEl().id);
35319 clearPanels : function(){
35320 while(this.panels.getCount() > 0){
35321 this.remove(this.panels.first());
35326 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35327 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35328 * @param {Boolean} preservePanel Overrides the config preservePanel option
35329 * @return {Roo.ContentPanel} The panel that was removed
35331 remove : function(panel, preservePanel)
35333 panel = this.getPanel(panel);
35338 this.fireEvent("beforeremove", this, panel, e);
35339 if(e.cancel === true){
35342 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35343 var panelId = panel.getId();
35344 this.panels.removeKey(panelId);
35346 document.body.appendChild(panel.getEl().dom);
35349 this.tabs.removeTab(panel.getEl().id);
35350 }else if (!preservePanel){
35351 this.bodyEl.dom.removeChild(panel.getEl().dom);
35353 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35354 var p = this.panels.first();
35355 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35356 tempEl.appendChild(p.getEl().dom);
35357 this.bodyEl.update("");
35358 this.bodyEl.dom.appendChild(p.getEl().dom);
35360 this.updateTitle(p.getTitle());
35362 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35363 this.setActivePanel(p);
35365 panel.setRegion(null);
35366 if(this.activePanel == panel){
35367 this.activePanel = null;
35369 if(this.config.autoDestroy !== false && preservePanel !== true){
35370 try{panel.destroy();}catch(e){}
35372 this.fireEvent("panelremoved", this, panel);
35377 * Returns the TabPanel component used by this region
35378 * @return {Roo.TabPanel}
35380 getTabs : function(){
35384 createTool : function(parentEl, className){
35385 var btn = Roo.DomHelper.append(parentEl, {
35387 cls: "x-layout-tools-button",
35390 cls: "roo-layout-tools-button-inner " + className,
35394 btn.addClassOnOver("roo-layout-tools-button-over");
35399 * Ext JS Library 1.1.1
35400 * Copyright(c) 2006-2007, Ext JS, LLC.
35402 * Originally Released Under LGPL - original licence link has changed is not relivant.
35405 * <script type="text/javascript">
35411 * @class Roo.SplitLayoutRegion
35412 * @extends Roo.LayoutRegion
35413 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35415 Roo.bootstrap.layout.Split = function(config){
35416 this.cursor = config.cursor;
35417 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35420 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35422 splitTip : "Drag to resize.",
35423 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35424 useSplitTips : false,
35426 applyConfig : function(config){
35427 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35430 onRender : function(ctr,pos) {
35432 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35433 if(!this.config.split){
35438 var splitEl = Roo.DomHelper.append(ctr.dom, {
35440 id: this.el.id + "-split",
35441 cls: "roo-layout-split roo-layout-split-"+this.position,
35444 /** The SplitBar for this region
35445 * @type Roo.SplitBar */
35446 // does not exist yet...
35447 Roo.log([this.position, this.orientation]);
35449 this.split = new Roo.bootstrap.SplitBar({
35450 dragElement : splitEl,
35451 resizingElement: this.el,
35452 orientation : this.orientation
35455 this.split.on("moved", this.onSplitMove, this);
35456 this.split.useShim = this.config.useShim === true;
35457 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35458 if(this.useSplitTips){
35459 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35461 //if(config.collapsible){
35462 // this.split.el.on("dblclick", this.collapse, this);
35465 if(typeof this.config.minSize != "undefined"){
35466 this.split.minSize = this.config.minSize;
35468 if(typeof this.config.maxSize != "undefined"){
35469 this.split.maxSize = this.config.maxSize;
35471 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35472 this.hideSplitter();
35477 getHMaxSize : function(){
35478 var cmax = this.config.maxSize || 10000;
35479 var center = this.mgr.getRegion("center");
35480 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35483 getVMaxSize : function(){
35484 var cmax = this.config.maxSize || 10000;
35485 var center = this.mgr.getRegion("center");
35486 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35489 onSplitMove : function(split, newSize){
35490 this.fireEvent("resized", this, newSize);
35494 * Returns the {@link Roo.SplitBar} for this region.
35495 * @return {Roo.SplitBar}
35497 getSplitBar : function(){
35502 this.hideSplitter();
35503 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35506 hideSplitter : function(){
35508 this.split.el.setLocation(-2000,-2000);
35509 this.split.el.hide();
35515 this.split.el.show();
35517 Roo.bootstrap.layout.Split.superclass.show.call(this);
35520 beforeSlide: function(){
35521 if(Roo.isGecko){// firefox overflow auto bug workaround
35522 this.bodyEl.clip();
35524 this.tabs.bodyEl.clip();
35526 if(this.activePanel){
35527 this.activePanel.getEl().clip();
35529 if(this.activePanel.beforeSlide){
35530 this.activePanel.beforeSlide();
35536 afterSlide : function(){
35537 if(Roo.isGecko){// firefox overflow auto bug workaround
35538 this.bodyEl.unclip();
35540 this.tabs.bodyEl.unclip();
35542 if(this.activePanel){
35543 this.activePanel.getEl().unclip();
35544 if(this.activePanel.afterSlide){
35545 this.activePanel.afterSlide();
35551 initAutoHide : function(){
35552 if(this.autoHide !== false){
35553 if(!this.autoHideHd){
35554 var st = new Roo.util.DelayedTask(this.slideIn, this);
35555 this.autoHideHd = {
35556 "mouseout": function(e){
35557 if(!e.within(this.el, true)){
35561 "mouseover" : function(e){
35567 this.el.on(this.autoHideHd);
35571 clearAutoHide : function(){
35572 if(this.autoHide !== false){
35573 this.el.un("mouseout", this.autoHideHd.mouseout);
35574 this.el.un("mouseover", this.autoHideHd.mouseover);
35578 clearMonitor : function(){
35579 Roo.get(document).un("click", this.slideInIf, this);
35582 // these names are backwards but not changed for compat
35583 slideOut : function(){
35584 if(this.isSlid || this.el.hasActiveFx()){
35587 this.isSlid = true;
35588 if(this.collapseBtn){
35589 this.collapseBtn.hide();
35591 this.closeBtnState = this.closeBtn.getStyle('display');
35592 this.closeBtn.hide();
35594 this.stickBtn.show();
35597 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35598 this.beforeSlide();
35599 this.el.setStyle("z-index", 10001);
35600 this.el.slideIn(this.getSlideAnchor(), {
35601 callback: function(){
35603 this.initAutoHide();
35604 Roo.get(document).on("click", this.slideInIf, this);
35605 this.fireEvent("slideshow", this);
35612 afterSlideIn : function(){
35613 this.clearAutoHide();
35614 this.isSlid = false;
35615 this.clearMonitor();
35616 this.el.setStyle("z-index", "");
35617 if(this.collapseBtn){
35618 this.collapseBtn.show();
35620 this.closeBtn.setStyle('display', this.closeBtnState);
35622 this.stickBtn.hide();
35624 this.fireEvent("slidehide", this);
35627 slideIn : function(cb){
35628 if(!this.isSlid || this.el.hasActiveFx()){
35632 this.isSlid = false;
35633 this.beforeSlide();
35634 this.el.slideOut(this.getSlideAnchor(), {
35635 callback: function(){
35636 this.el.setLeftTop(-10000, -10000);
35638 this.afterSlideIn();
35646 slideInIf : function(e){
35647 if(!e.within(this.el)){
35652 animateCollapse : function(){
35653 this.beforeSlide();
35654 this.el.setStyle("z-index", 20000);
35655 var anchor = this.getSlideAnchor();
35656 this.el.slideOut(anchor, {
35657 callback : function(){
35658 this.el.setStyle("z-index", "");
35659 this.collapsedEl.slideIn(anchor, {duration:.3});
35661 this.el.setLocation(-10000,-10000);
35663 this.fireEvent("collapsed", this);
35670 animateExpand : function(){
35671 this.beforeSlide();
35672 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35673 this.el.setStyle("z-index", 20000);
35674 this.collapsedEl.hide({
35677 this.el.slideIn(this.getSlideAnchor(), {
35678 callback : function(){
35679 this.el.setStyle("z-index", "");
35682 this.split.el.show();
35684 this.fireEvent("invalidated", this);
35685 this.fireEvent("expanded", this);
35713 getAnchor : function(){
35714 return this.anchors[this.position];
35717 getCollapseAnchor : function(){
35718 return this.canchors[this.position];
35721 getSlideAnchor : function(){
35722 return this.sanchors[this.position];
35725 getAlignAdj : function(){
35726 var cm = this.cmargins;
35727 switch(this.position){
35743 getExpandAdj : function(){
35744 var c = this.collapsedEl, cm = this.cmargins;
35745 switch(this.position){
35747 return [-(cm.right+c.getWidth()+cm.left), 0];
35750 return [cm.right+c.getWidth()+cm.left, 0];
35753 return [0, -(cm.top+cm.bottom+c.getHeight())];
35756 return [0, cm.top+cm.bottom+c.getHeight()];
35762 * Ext JS Library 1.1.1
35763 * Copyright(c) 2006-2007, Ext JS, LLC.
35765 * Originally Released Under LGPL - original licence link has changed is not relivant.
35768 * <script type="text/javascript">
35771 * These classes are private internal classes
35773 Roo.bootstrap.layout.Center = function(config){
35774 config.region = "center";
35775 Roo.bootstrap.layout.Region.call(this, config);
35776 this.visible = true;
35777 this.minWidth = config.minWidth || 20;
35778 this.minHeight = config.minHeight || 20;
35781 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35783 // center panel can't be hidden
35787 // center panel can't be hidden
35790 getMinWidth: function(){
35791 return this.minWidth;
35794 getMinHeight: function(){
35795 return this.minHeight;
35808 Roo.bootstrap.layout.North = function(config)
35810 config.region = 'north';
35811 config.cursor = 'n-resize';
35813 Roo.bootstrap.layout.Split.call(this, config);
35817 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35818 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35819 this.split.el.addClass("roo-layout-split-v");
35821 var size = config.initialSize || config.height;
35822 if(typeof size != "undefined"){
35823 this.el.setHeight(size);
35826 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35828 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35832 getBox : function(){
35833 if(this.collapsed){
35834 return this.collapsedEl.getBox();
35836 var box = this.el.getBox();
35838 box.height += this.split.el.getHeight();
35843 updateBox : function(box){
35844 if(this.split && !this.collapsed){
35845 box.height -= this.split.el.getHeight();
35846 this.split.el.setLeft(box.x);
35847 this.split.el.setTop(box.y+box.height);
35848 this.split.el.setWidth(box.width);
35850 if(this.collapsed){
35851 this.updateBody(box.width, null);
35853 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35861 Roo.bootstrap.layout.South = function(config){
35862 config.region = 'south';
35863 config.cursor = 's-resize';
35864 Roo.bootstrap.layout.Split.call(this, config);
35866 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35867 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35868 this.split.el.addClass("roo-layout-split-v");
35870 var size = config.initialSize || config.height;
35871 if(typeof size != "undefined"){
35872 this.el.setHeight(size);
35876 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35877 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35878 getBox : function(){
35879 if(this.collapsed){
35880 return this.collapsedEl.getBox();
35882 var box = this.el.getBox();
35884 var sh = this.split.el.getHeight();
35891 updateBox : function(box){
35892 if(this.split && !this.collapsed){
35893 var sh = this.split.el.getHeight();
35896 this.split.el.setLeft(box.x);
35897 this.split.el.setTop(box.y-sh);
35898 this.split.el.setWidth(box.width);
35900 if(this.collapsed){
35901 this.updateBody(box.width, null);
35903 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35907 Roo.bootstrap.layout.East = function(config){
35908 config.region = "east";
35909 config.cursor = "e-resize";
35910 Roo.bootstrap.layout.Split.call(this, config);
35912 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35913 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35914 this.split.el.addClass("roo-layout-split-h");
35916 var size = config.initialSize || config.width;
35917 if(typeof size != "undefined"){
35918 this.el.setWidth(size);
35921 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35922 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35923 getBox : function(){
35924 if(this.collapsed){
35925 return this.collapsedEl.getBox();
35927 var box = this.el.getBox();
35929 var sw = this.split.el.getWidth();
35936 updateBox : function(box){
35937 if(this.split && !this.collapsed){
35938 var sw = this.split.el.getWidth();
35940 this.split.el.setLeft(box.x);
35941 this.split.el.setTop(box.y);
35942 this.split.el.setHeight(box.height);
35945 if(this.collapsed){
35946 this.updateBody(null, box.height);
35948 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35952 Roo.bootstrap.layout.West = function(config){
35953 config.region = "west";
35954 config.cursor = "w-resize";
35956 Roo.bootstrap.layout.Split.call(this, config);
35958 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35959 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35960 this.split.el.addClass("roo-layout-split-h");
35964 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35965 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35967 onRender: function(ctr, pos)
35969 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35970 var size = this.config.initialSize || this.config.width;
35971 if(typeof size != "undefined"){
35972 this.el.setWidth(size);
35976 getBox : function(){
35977 if(this.collapsed){
35978 return this.collapsedEl.getBox();
35980 var box = this.el.getBox();
35982 box.width += this.split.el.getWidth();
35987 updateBox : function(box){
35988 if(this.split && !this.collapsed){
35989 var sw = this.split.el.getWidth();
35991 this.split.el.setLeft(box.x+box.width);
35992 this.split.el.setTop(box.y);
35993 this.split.el.setHeight(box.height);
35995 if(this.collapsed){
35996 this.updateBody(null, box.height);
35998 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36001 Roo.namespace("Roo.bootstrap.panel");/*
36003 * Ext JS Library 1.1.1
36004 * Copyright(c) 2006-2007, Ext JS, LLC.
36006 * Originally Released Under LGPL - original licence link has changed is not relivant.
36009 * <script type="text/javascript">
36012 * @class Roo.ContentPanel
36013 * @extends Roo.util.Observable
36014 * A basic ContentPanel element.
36015 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36016 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36017 * @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
36018 * @cfg {Boolean} closable True if the panel can be closed/removed
36019 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36020 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36021 * @cfg {Toolbar} toolbar A toolbar for this panel
36022 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36023 * @cfg {String} title The title for this panel
36024 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36025 * @cfg {String} url Calls {@link #setUrl} with this value
36026 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36027 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36028 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36029 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36030 * @cfg {Boolean} badges render the badges
36033 * Create a new ContentPanel.
36034 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36035 * @param {String/Object} config A string to set only the title or a config object
36036 * @param {String} content (optional) Set the HTML content for this panel
36037 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36039 Roo.bootstrap.panel.Content = function( config){
36041 this.tpl = config.tpl || false;
36043 var el = config.el;
36044 var content = config.content;
36046 if(config.autoCreate){ // xtype is available if this is called from factory
36049 this.el = Roo.get(el);
36050 if(!this.el && config && config.autoCreate){
36051 if(typeof config.autoCreate == "object"){
36052 if(!config.autoCreate.id){
36053 config.autoCreate.id = config.id||el;
36055 this.el = Roo.DomHelper.append(document.body,
36056 config.autoCreate, true);
36058 var elcfg = { tag: "div",
36059 cls: "roo-layout-inactive-content",
36063 elcfg.html = config.html;
36067 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36070 this.closable = false;
36071 this.loaded = false;
36072 this.active = false;
36075 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36077 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36079 this.wrapEl = this.el; //this.el.wrap();
36081 if (config.toolbar.items) {
36082 ti = config.toolbar.items ;
36083 delete config.toolbar.items ;
36087 this.toolbar.render(this.wrapEl, 'before');
36088 for(var i =0;i < ti.length;i++) {
36089 // Roo.log(['add child', items[i]]);
36090 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36092 this.toolbar.items = nitems;
36093 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36094 delete config.toolbar;
36098 // xtype created footer. - not sure if will work as we normally have to render first..
36099 if (this.footer && !this.footer.el && this.footer.xtype) {
36100 if (!this.wrapEl) {
36101 this.wrapEl = this.el.wrap();
36104 this.footer.container = this.wrapEl.createChild();
36106 this.footer = Roo.factory(this.footer, Roo);
36111 if(typeof config == "string"){
36112 this.title = config;
36114 Roo.apply(this, config);
36118 this.resizeEl = Roo.get(this.resizeEl, true);
36120 this.resizeEl = this.el;
36122 // handle view.xtype
36130 * Fires when this panel is activated.
36131 * @param {Roo.ContentPanel} this
36135 * @event deactivate
36136 * Fires when this panel is activated.
36137 * @param {Roo.ContentPanel} this
36139 "deactivate" : true,
36143 * Fires when this panel is resized if fitToFrame is true.
36144 * @param {Roo.ContentPanel} this
36145 * @param {Number} width The width after any component adjustments
36146 * @param {Number} height The height after any component adjustments
36152 * Fires when this tab is created
36153 * @param {Roo.ContentPanel} this
36164 if(this.autoScroll){
36165 this.resizeEl.setStyle("overflow", "auto");
36167 // fix randome scrolling
36168 //this.el.on('scroll', function() {
36169 // Roo.log('fix random scolling');
36170 // this.scrollTo('top',0);
36173 content = content || this.content;
36175 this.setContent(content);
36177 if(config && config.url){
36178 this.setUrl(this.url, this.params, this.loadOnce);
36183 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36185 if (this.view && typeof(this.view.xtype) != 'undefined') {
36186 this.view.el = this.el.appendChild(document.createElement("div"));
36187 this.view = Roo.factory(this.view);
36188 this.view.render && this.view.render(false, '');
36192 this.fireEvent('render', this);
36195 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36199 setRegion : function(region){
36200 this.region = region;
36201 this.setActiveClass(region && !this.background);
36205 setActiveClass: function(state)
36208 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36209 this.el.setStyle('position','relative');
36211 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36212 this.el.setStyle('position', 'absolute');
36217 * Returns the toolbar for this Panel if one was configured.
36218 * @return {Roo.Toolbar}
36220 getToolbar : function(){
36221 return this.toolbar;
36224 setActiveState : function(active)
36226 this.active = active;
36227 this.setActiveClass(active);
36229 this.fireEvent("deactivate", this);
36231 this.fireEvent("activate", this);
36235 * Updates this panel's element
36236 * @param {String} content The new content
36237 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36239 setContent : function(content, loadScripts){
36240 this.el.update(content, loadScripts);
36243 ignoreResize : function(w, h){
36244 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36247 this.lastSize = {width: w, height: h};
36252 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36253 * @return {Roo.UpdateManager} The UpdateManager
36255 getUpdateManager : function(){
36256 return this.el.getUpdateManager();
36259 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36260 * @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:
36263 url: "your-url.php",
36264 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36265 callback: yourFunction,
36266 scope: yourObject, //(optional scope)
36269 text: "Loading...",
36274 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36275 * 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.
36276 * @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}
36277 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36278 * @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.
36279 * @return {Roo.ContentPanel} this
36282 var um = this.el.getUpdateManager();
36283 um.update.apply(um, arguments);
36289 * 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.
36290 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36291 * @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)
36292 * @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)
36293 * @return {Roo.UpdateManager} The UpdateManager
36295 setUrl : function(url, params, loadOnce){
36296 if(this.refreshDelegate){
36297 this.removeListener("activate", this.refreshDelegate);
36299 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36300 this.on("activate", this.refreshDelegate);
36301 return this.el.getUpdateManager();
36304 _handleRefresh : function(url, params, loadOnce){
36305 if(!loadOnce || !this.loaded){
36306 var updater = this.el.getUpdateManager();
36307 updater.update(url, params, this._setLoaded.createDelegate(this));
36311 _setLoaded : function(){
36312 this.loaded = true;
36316 * Returns this panel's id
36319 getId : function(){
36324 * Returns this panel's element - used by regiosn to add.
36325 * @return {Roo.Element}
36327 getEl : function(){
36328 return this.wrapEl || this.el;
36333 adjustForComponents : function(width, height)
36335 //Roo.log('adjustForComponents ');
36336 if(this.resizeEl != this.el){
36337 width -= this.el.getFrameWidth('lr');
36338 height -= this.el.getFrameWidth('tb');
36341 var te = this.toolbar.getEl();
36342 te.setWidth(width);
36343 height -= te.getHeight();
36346 var te = this.footer.getEl();
36347 te.setWidth(width);
36348 height -= te.getHeight();
36352 if(this.adjustments){
36353 width += this.adjustments[0];
36354 height += this.adjustments[1];
36356 return {"width": width, "height": height};
36359 setSize : function(width, height){
36360 if(this.fitToFrame && !this.ignoreResize(width, height)){
36361 if(this.fitContainer && this.resizeEl != this.el){
36362 this.el.setSize(width, height);
36364 var size = this.adjustForComponents(width, height);
36365 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36366 this.fireEvent('resize', this, size.width, size.height);
36371 * Returns this panel's title
36374 getTitle : function(){
36376 if (typeof(this.title) != 'object') {
36381 for (var k in this.title) {
36382 if (!this.title.hasOwnProperty(k)) {
36386 if (k.indexOf('-') >= 0) {
36387 var s = k.split('-');
36388 for (var i = 0; i<s.length; i++) {
36389 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36392 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36399 * Set this panel's title
36400 * @param {String} title
36402 setTitle : function(title){
36403 this.title = title;
36405 this.region.updatePanelTitle(this, title);
36410 * Returns true is this panel was configured to be closable
36411 * @return {Boolean}
36413 isClosable : function(){
36414 return this.closable;
36417 beforeSlide : function(){
36419 this.resizeEl.clip();
36422 afterSlide : function(){
36424 this.resizeEl.unclip();
36428 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36429 * Will fail silently if the {@link #setUrl} method has not been called.
36430 * This does not activate the panel, just updates its content.
36432 refresh : function(){
36433 if(this.refreshDelegate){
36434 this.loaded = false;
36435 this.refreshDelegate();
36440 * Destroys this panel
36442 destroy : function(){
36443 this.el.removeAllListeners();
36444 var tempEl = document.createElement("span");
36445 tempEl.appendChild(this.el.dom);
36446 tempEl.innerHTML = "";
36452 * form - if the content panel contains a form - this is a reference to it.
36453 * @type {Roo.form.Form}
36457 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36458 * This contains a reference to it.
36464 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36474 * @param {Object} cfg Xtype definition of item to add.
36478 getChildContainer: function () {
36479 return this.getEl();
36484 var ret = new Roo.factory(cfg);
36489 if (cfg.xtype.match(/^Form$/)) {
36492 //if (this.footer) {
36493 // el = this.footer.container.insertSibling(false, 'before');
36495 el = this.el.createChild();
36498 this.form = new Roo.form.Form(cfg);
36501 if ( this.form.allItems.length) {
36502 this.form.render(el.dom);
36506 // should only have one of theses..
36507 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36508 // views.. should not be just added - used named prop 'view''
36510 cfg.el = this.el.appendChild(document.createElement("div"));
36513 var ret = new Roo.factory(cfg);
36515 ret.render && ret.render(false, ''); // render blank..
36525 * @class Roo.bootstrap.panel.Grid
36526 * @extends Roo.bootstrap.panel.Content
36528 * Create a new GridPanel.
36529 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36530 * @param {Object} config A the config object
36536 Roo.bootstrap.panel.Grid = function(config)
36540 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36541 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36543 config.el = this.wrapper;
36544 //this.el = this.wrapper;
36546 if (config.container) {
36547 // ctor'ed from a Border/panel.grid
36550 this.wrapper.setStyle("overflow", "hidden");
36551 this.wrapper.addClass('roo-grid-container');
36556 if(config.toolbar){
36557 var tool_el = this.wrapper.createChild();
36558 this.toolbar = Roo.factory(config.toolbar);
36560 if (config.toolbar.items) {
36561 ti = config.toolbar.items ;
36562 delete config.toolbar.items ;
36566 this.toolbar.render(tool_el);
36567 for(var i =0;i < ti.length;i++) {
36568 // Roo.log(['add child', items[i]]);
36569 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36571 this.toolbar.items = nitems;
36573 delete config.toolbar;
36576 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36577 config.grid.scrollBody = true;;
36578 config.grid.monitorWindowResize = false; // turn off autosizing
36579 config.grid.autoHeight = false;
36580 config.grid.autoWidth = false;
36582 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36584 if (config.background) {
36585 // render grid on panel activation (if panel background)
36586 this.on('activate', function(gp) {
36587 if (!gp.grid.rendered) {
36588 gp.grid.render(this.wrapper);
36589 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36594 this.grid.render(this.wrapper);
36595 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36598 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36599 // ??? needed ??? config.el = this.wrapper;
36604 // xtype created footer. - not sure if will work as we normally have to render first..
36605 if (this.footer && !this.footer.el && this.footer.xtype) {
36607 var ctr = this.grid.getView().getFooterPanel(true);
36608 this.footer.dataSource = this.grid.dataSource;
36609 this.footer = Roo.factory(this.footer, Roo);
36610 this.footer.render(ctr);
36620 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36621 getId : function(){
36622 return this.grid.id;
36626 * Returns the grid for this panel
36627 * @return {Roo.bootstrap.Table}
36629 getGrid : function(){
36633 setSize : function(width, height){
36634 if(!this.ignoreResize(width, height)){
36635 var grid = this.grid;
36636 var size = this.adjustForComponents(width, height);
36637 var gridel = grid.getGridEl();
36638 gridel.setSize(size.width, size.height);
36640 var thd = grid.getGridEl().select('thead',true).first();
36641 var tbd = grid.getGridEl().select('tbody', true).first();
36643 tbd.setSize(width, height - thd.getHeight());
36652 beforeSlide : function(){
36653 this.grid.getView().scroller.clip();
36656 afterSlide : function(){
36657 this.grid.getView().scroller.unclip();
36660 destroy : function(){
36661 this.grid.destroy();
36663 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36668 * @class Roo.bootstrap.panel.Nest
36669 * @extends Roo.bootstrap.panel.Content
36671 * Create a new Panel, that can contain a layout.Border.
36674 * @param {Roo.BorderLayout} layout The layout for this panel
36675 * @param {String/Object} config A string to set only the title or a config object
36677 Roo.bootstrap.panel.Nest = function(config)
36679 // construct with only one argument..
36680 /* FIXME - implement nicer consturctors
36681 if (layout.layout) {
36683 layout = config.layout;
36684 delete config.layout;
36686 if (layout.xtype && !layout.getEl) {
36687 // then layout needs constructing..
36688 layout = Roo.factory(layout, Roo);
36692 config.el = config.layout.getEl();
36694 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36696 config.layout.monitorWindowResize = false; // turn off autosizing
36697 this.layout = config.layout;
36698 this.layout.getEl().addClass("roo-layout-nested-layout");
36705 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36707 setSize : function(width, height){
36708 if(!this.ignoreResize(width, height)){
36709 var size = this.adjustForComponents(width, height);
36710 var el = this.layout.getEl();
36711 if (size.height < 1) {
36712 el.setWidth(size.width);
36714 el.setSize(size.width, size.height);
36716 var touch = el.dom.offsetWidth;
36717 this.layout.layout();
36718 // ie requires a double layout on the first pass
36719 if(Roo.isIE && !this.initialized){
36720 this.initialized = true;
36721 this.layout.layout();
36726 // activate all subpanels if not currently active..
36728 setActiveState : function(active){
36729 this.active = active;
36730 this.setActiveClass(active);
36733 this.fireEvent("deactivate", this);
36737 this.fireEvent("activate", this);
36738 // not sure if this should happen before or after..
36739 if (!this.layout) {
36740 return; // should not happen..
36743 for (var r in this.layout.regions) {
36744 reg = this.layout.getRegion(r);
36745 if (reg.getActivePanel()) {
36746 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36747 reg.setActivePanel(reg.getActivePanel());
36750 if (!reg.panels.length) {
36753 reg.showPanel(reg.getPanel(0));
36762 * Returns the nested BorderLayout for this panel
36763 * @return {Roo.BorderLayout}
36765 getLayout : function(){
36766 return this.layout;
36770 * Adds a xtype elements to the layout of the nested panel
36774 xtype : 'ContentPanel',
36781 xtype : 'NestedLayoutPanel',
36787 items : [ ... list of content panels or nested layout panels.. ]
36791 * @param {Object} cfg Xtype definition of item to add.
36793 addxtype : function(cfg) {
36794 return this.layout.addxtype(cfg);
36799 * Ext JS Library 1.1.1
36800 * Copyright(c) 2006-2007, Ext JS, LLC.
36802 * Originally Released Under LGPL - original licence link has changed is not relivant.
36805 * <script type="text/javascript">
36808 * @class Roo.TabPanel
36809 * @extends Roo.util.Observable
36810 * A lightweight tab container.
36814 // basic tabs 1, built from existing content
36815 var tabs = new Roo.TabPanel("tabs1");
36816 tabs.addTab("script", "View Script");
36817 tabs.addTab("markup", "View Markup");
36818 tabs.activate("script");
36820 // more advanced tabs, built from javascript
36821 var jtabs = new Roo.TabPanel("jtabs");
36822 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36824 // set up the UpdateManager
36825 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36826 var updater = tab2.getUpdateManager();
36827 updater.setDefaultUrl("ajax1.htm");
36828 tab2.on('activate', updater.refresh, updater, true);
36830 // Use setUrl for Ajax loading
36831 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36832 tab3.setUrl("ajax2.htm", null, true);
36835 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36838 jtabs.activate("jtabs-1");
36841 * Create a new TabPanel.
36842 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36843 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36845 Roo.bootstrap.panel.Tabs = function(config){
36847 * The container element for this TabPanel.
36848 * @type Roo.Element
36850 this.el = Roo.get(config.el);
36853 if(typeof config == "boolean"){
36854 this.tabPosition = config ? "bottom" : "top";
36856 Roo.apply(this, config);
36860 if(this.tabPosition == "bottom"){
36861 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36862 this.el.addClass("roo-tabs-bottom");
36864 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36865 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36866 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36868 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36870 if(this.tabPosition != "bottom"){
36871 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36872 * @type Roo.Element
36874 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36875 this.el.addClass("roo-tabs-top");
36879 this.bodyEl.setStyle("position", "relative");
36881 this.active = null;
36882 this.activateDelegate = this.activate.createDelegate(this);
36887 * Fires when the active tab changes
36888 * @param {Roo.TabPanel} this
36889 * @param {Roo.TabPanelItem} activePanel The new active tab
36893 * @event beforetabchange
36894 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36895 * @param {Roo.TabPanel} this
36896 * @param {Object} e Set cancel to true on this object to cancel the tab change
36897 * @param {Roo.TabPanelItem} tab The tab being changed to
36899 "beforetabchange" : true
36902 Roo.EventManager.onWindowResize(this.onResize, this);
36903 this.cpad = this.el.getPadding("lr");
36904 this.hiddenCount = 0;
36907 // toolbar on the tabbar support...
36908 if (this.toolbar) {
36909 alert("no toolbar support yet");
36910 this.toolbar = false;
36912 var tcfg = this.toolbar;
36913 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36914 this.toolbar = new Roo.Toolbar(tcfg);
36915 if (Roo.isSafari) {
36916 var tbl = tcfg.container.child('table', true);
36917 tbl.setAttribute('width', '100%');
36925 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36928 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36930 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36932 tabPosition : "top",
36934 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36936 currentTabWidth : 0,
36938 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36942 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36946 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36948 preferredTabWidth : 175,
36950 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36952 resizeTabs : false,
36954 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36956 monitorResize : true,
36958 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36963 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36964 * @param {String} id The id of the div to use <b>or create</b>
36965 * @param {String} text The text for the tab
36966 * @param {String} content (optional) Content to put in the TabPanelItem body
36967 * @param {Boolean} closable (optional) True to create a close icon on the tab
36968 * @return {Roo.TabPanelItem} The created TabPanelItem
36970 addTab : function(id, text, content, closable, tpl)
36972 var item = new Roo.bootstrap.panel.TabItem({
36976 closable : closable,
36979 this.addTabItem(item);
36981 item.setContent(content);
36987 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36988 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36989 * @return {Roo.TabPanelItem}
36991 getTab : function(id){
36992 return this.items[id];
36996 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36997 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36999 hideTab : function(id){
37000 var t = this.items[id];
37003 this.hiddenCount++;
37004 this.autoSizeTabs();
37009 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37010 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37012 unhideTab : function(id){
37013 var t = this.items[id];
37015 t.setHidden(false);
37016 this.hiddenCount--;
37017 this.autoSizeTabs();
37022 * Adds an existing {@link Roo.TabPanelItem}.
37023 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37025 addTabItem : function(item){
37026 this.items[item.id] = item;
37027 this.items.push(item);
37028 // if(this.resizeTabs){
37029 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37030 // this.autoSizeTabs();
37032 // item.autoSize();
37037 * Removes a {@link Roo.TabPanelItem}.
37038 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37040 removeTab : function(id){
37041 var items = this.items;
37042 var tab = items[id];
37043 if(!tab) { return; }
37044 var index = items.indexOf(tab);
37045 if(this.active == tab && items.length > 1){
37046 var newTab = this.getNextAvailable(index);
37051 this.stripEl.dom.removeChild(tab.pnode.dom);
37052 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37053 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37055 items.splice(index, 1);
37056 delete this.items[tab.id];
37057 tab.fireEvent("close", tab);
37058 tab.purgeListeners();
37059 this.autoSizeTabs();
37062 getNextAvailable : function(start){
37063 var items = this.items;
37065 // look for a next tab that will slide over to
37066 // replace the one being removed
37067 while(index < items.length){
37068 var item = items[++index];
37069 if(item && !item.isHidden()){
37073 // if one isn't found select the previous tab (on the left)
37076 var item = items[--index];
37077 if(item && !item.isHidden()){
37085 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37086 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37088 disableTab : function(id){
37089 var tab = this.items[id];
37090 if(tab && this.active != tab){
37096 * Enables a {@link Roo.TabPanelItem} that is disabled.
37097 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37099 enableTab : function(id){
37100 var tab = this.items[id];
37105 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37106 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37107 * @return {Roo.TabPanelItem} The TabPanelItem.
37109 activate : function(id){
37110 var tab = this.items[id];
37114 if(tab == this.active || tab.disabled){
37118 this.fireEvent("beforetabchange", this, e, tab);
37119 if(e.cancel !== true && !tab.disabled){
37121 this.active.hide();
37123 this.active = this.items[id];
37124 this.active.show();
37125 this.fireEvent("tabchange", this, this.active);
37131 * Gets the active {@link Roo.TabPanelItem}.
37132 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37134 getActiveTab : function(){
37135 return this.active;
37139 * Updates the tab body element to fit the height of the container element
37140 * for overflow scrolling
37141 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37143 syncHeight : function(targetHeight){
37144 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37145 var bm = this.bodyEl.getMargins();
37146 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37147 this.bodyEl.setHeight(newHeight);
37151 onResize : function(){
37152 if(this.monitorResize){
37153 this.autoSizeTabs();
37158 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37160 beginUpdate : function(){
37161 this.updating = true;
37165 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37167 endUpdate : function(){
37168 this.updating = false;
37169 this.autoSizeTabs();
37173 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37175 autoSizeTabs : function(){
37176 var count = this.items.length;
37177 var vcount = count - this.hiddenCount;
37178 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37181 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37182 var availWidth = Math.floor(w / vcount);
37183 var b = this.stripBody;
37184 if(b.getWidth() > w){
37185 var tabs = this.items;
37186 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37187 if(availWidth < this.minTabWidth){
37188 /*if(!this.sleft){ // incomplete scrolling code
37189 this.createScrollButtons();
37192 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37195 if(this.currentTabWidth < this.preferredTabWidth){
37196 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37202 * Returns the number of tabs in this TabPanel.
37205 getCount : function(){
37206 return this.items.length;
37210 * Resizes all the tabs to the passed width
37211 * @param {Number} The new width
37213 setTabWidth : function(width){
37214 this.currentTabWidth = width;
37215 for(var i = 0, len = this.items.length; i < len; i++) {
37216 if(!this.items[i].isHidden()) {
37217 this.items[i].setWidth(width);
37223 * Destroys this TabPanel
37224 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37226 destroy : function(removeEl){
37227 Roo.EventManager.removeResizeListener(this.onResize, this);
37228 for(var i = 0, len = this.items.length; i < len; i++){
37229 this.items[i].purgeListeners();
37231 if(removeEl === true){
37232 this.el.update("");
37237 createStrip : function(container)
37239 var strip = document.createElement("nav");
37240 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37241 container.appendChild(strip);
37245 createStripList : function(strip)
37247 // div wrapper for retard IE
37248 // returns the "tr" element.
37249 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37250 //'<div class="x-tabs-strip-wrap">'+
37251 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37252 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37253 return strip.firstChild; //.firstChild.firstChild.firstChild;
37255 createBody : function(container)
37257 var body = document.createElement("div");
37258 Roo.id(body, "tab-body");
37259 //Roo.fly(body).addClass("x-tabs-body");
37260 Roo.fly(body).addClass("tab-content");
37261 container.appendChild(body);
37264 createItemBody :function(bodyEl, id){
37265 var body = Roo.getDom(id);
37267 body = document.createElement("div");
37270 //Roo.fly(body).addClass("x-tabs-item-body");
37271 Roo.fly(body).addClass("tab-pane");
37272 bodyEl.insertBefore(body, bodyEl.firstChild);
37276 createStripElements : function(stripEl, text, closable, tpl)
37278 var td = document.createElement("li"); // was td..
37281 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37284 stripEl.appendChild(td);
37286 td.className = "x-tabs-closable";
37287 if(!this.closeTpl){
37288 this.closeTpl = new Roo.Template(
37289 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37290 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37291 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37294 var el = this.closeTpl.overwrite(td, {"text": text});
37295 var close = el.getElementsByTagName("div")[0];
37296 var inner = el.getElementsByTagName("em")[0];
37297 return {"el": el, "close": close, "inner": inner};
37300 // not sure what this is..
37301 // if(!this.tabTpl){
37302 //this.tabTpl = new Roo.Template(
37303 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37304 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37306 // this.tabTpl = new Roo.Template(
37307 // '<a href="#">' +
37308 // '<span unselectable="on"' +
37309 // (this.disableTooltips ? '' : ' title="{text}"') +
37310 // ' >{text}</span></a>'
37316 var template = tpl || this.tabTpl || false;
37320 template = new Roo.Template(
37322 '<span unselectable="on"' +
37323 (this.disableTooltips ? '' : ' title="{text}"') +
37324 ' >{text}</span></a>'
37328 switch (typeof(template)) {
37332 template = new Roo.Template(template);
37338 var el = template.overwrite(td, {"text": text});
37340 var inner = el.getElementsByTagName("span")[0];
37342 return {"el": el, "inner": inner};
37350 * @class Roo.TabPanelItem
37351 * @extends Roo.util.Observable
37352 * Represents an individual item (tab plus body) in a TabPanel.
37353 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37354 * @param {String} id The id of this TabPanelItem
37355 * @param {String} text The text for the tab of this TabPanelItem
37356 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37358 Roo.bootstrap.panel.TabItem = function(config){
37360 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37361 * @type Roo.TabPanel
37363 this.tabPanel = config.panel;
37365 * The id for this TabPanelItem
37368 this.id = config.id;
37370 this.disabled = false;
37372 this.text = config.text;
37374 this.loaded = false;
37375 this.closable = config.closable;
37378 * The body element for this TabPanelItem.
37379 * @type Roo.Element
37381 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37382 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37383 this.bodyEl.setStyle("display", "block");
37384 this.bodyEl.setStyle("zoom", "1");
37385 //this.hideAction();
37387 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37389 this.el = Roo.get(els.el);
37390 this.inner = Roo.get(els.inner, true);
37391 this.textEl = Roo.get(this.el.dom.firstChild, true);
37392 this.pnode = Roo.get(els.el.parentNode, true);
37393 this.el.on("mousedown", this.onTabMouseDown, this);
37394 this.el.on("click", this.onTabClick, this);
37396 if(config.closable){
37397 var c = Roo.get(els.close, true);
37398 c.dom.title = this.closeText;
37399 c.addClassOnOver("close-over");
37400 c.on("click", this.closeClick, this);
37406 * Fires when this tab becomes the active tab.
37407 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37408 * @param {Roo.TabPanelItem} this
37412 * @event beforeclose
37413 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37414 * @param {Roo.TabPanelItem} this
37415 * @param {Object} e Set cancel to true on this object to cancel the close.
37417 "beforeclose": true,
37420 * Fires when this tab is closed.
37421 * @param {Roo.TabPanelItem} this
37425 * @event deactivate
37426 * Fires when this tab is no longer the active tab.
37427 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37428 * @param {Roo.TabPanelItem} this
37430 "deactivate" : true
37432 this.hidden = false;
37434 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37437 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37439 purgeListeners : function(){
37440 Roo.util.Observable.prototype.purgeListeners.call(this);
37441 this.el.removeAllListeners();
37444 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37447 this.pnode.addClass("active");
37450 this.tabPanel.stripWrap.repaint();
37452 this.fireEvent("activate", this.tabPanel, this);
37456 * Returns true if this tab is the active tab.
37457 * @return {Boolean}
37459 isActive : function(){
37460 return this.tabPanel.getActiveTab() == this;
37464 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37467 this.pnode.removeClass("active");
37469 this.fireEvent("deactivate", this.tabPanel, this);
37472 hideAction : function(){
37473 this.bodyEl.hide();
37474 this.bodyEl.setStyle("position", "absolute");
37475 this.bodyEl.setLeft("-20000px");
37476 this.bodyEl.setTop("-20000px");
37479 showAction : function(){
37480 this.bodyEl.setStyle("position", "relative");
37481 this.bodyEl.setTop("");
37482 this.bodyEl.setLeft("");
37483 this.bodyEl.show();
37487 * Set the tooltip for the tab.
37488 * @param {String} tooltip The tab's tooltip
37490 setTooltip : function(text){
37491 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37492 this.textEl.dom.qtip = text;
37493 this.textEl.dom.removeAttribute('title');
37495 this.textEl.dom.title = text;
37499 onTabClick : function(e){
37500 e.preventDefault();
37501 this.tabPanel.activate(this.id);
37504 onTabMouseDown : function(e){
37505 e.preventDefault();
37506 this.tabPanel.activate(this.id);
37509 getWidth : function(){
37510 return this.inner.getWidth();
37513 setWidth : function(width){
37514 var iwidth = width - this.pnode.getPadding("lr");
37515 this.inner.setWidth(iwidth);
37516 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37517 this.pnode.setWidth(width);
37521 * Show or hide the tab
37522 * @param {Boolean} hidden True to hide or false to show.
37524 setHidden : function(hidden){
37525 this.hidden = hidden;
37526 this.pnode.setStyle("display", hidden ? "none" : "");
37530 * Returns true if this tab is "hidden"
37531 * @return {Boolean}
37533 isHidden : function(){
37534 return this.hidden;
37538 * Returns the text for this tab
37541 getText : function(){
37545 autoSize : function(){
37546 //this.el.beginMeasure();
37547 this.textEl.setWidth(1);
37549 * #2804 [new] Tabs in Roojs
37550 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37552 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37553 //this.el.endMeasure();
37557 * Sets the text for the tab (Note: this also sets the tooltip text)
37558 * @param {String} text The tab's text and tooltip
37560 setText : function(text){
37562 this.textEl.update(text);
37563 this.setTooltip(text);
37564 //if(!this.tabPanel.resizeTabs){
37565 // this.autoSize();
37569 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37571 activate : function(){
37572 this.tabPanel.activate(this.id);
37576 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37578 disable : function(){
37579 if(this.tabPanel.active != this){
37580 this.disabled = true;
37581 this.pnode.addClass("disabled");
37586 * Enables this TabPanelItem if it was previously disabled.
37588 enable : function(){
37589 this.disabled = false;
37590 this.pnode.removeClass("disabled");
37594 * Sets the content for this TabPanelItem.
37595 * @param {String} content The content
37596 * @param {Boolean} loadScripts true to look for and load scripts
37598 setContent : function(content, loadScripts){
37599 this.bodyEl.update(content, loadScripts);
37603 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37604 * @return {Roo.UpdateManager} The UpdateManager
37606 getUpdateManager : function(){
37607 return this.bodyEl.getUpdateManager();
37611 * Set a URL to be used to load the content for this TabPanelItem.
37612 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37613 * @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)
37614 * @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)
37615 * @return {Roo.UpdateManager} The UpdateManager
37617 setUrl : function(url, params, loadOnce){
37618 if(this.refreshDelegate){
37619 this.un('activate', this.refreshDelegate);
37621 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37622 this.on("activate", this.refreshDelegate);
37623 return this.bodyEl.getUpdateManager();
37627 _handleRefresh : function(url, params, loadOnce){
37628 if(!loadOnce || !this.loaded){
37629 var updater = this.bodyEl.getUpdateManager();
37630 updater.update(url, params, this._setLoaded.createDelegate(this));
37635 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37636 * Will fail silently if the setUrl method has not been called.
37637 * This does not activate the panel, just updates its content.
37639 refresh : function(){
37640 if(this.refreshDelegate){
37641 this.loaded = false;
37642 this.refreshDelegate();
37647 _setLoaded : function(){
37648 this.loaded = true;
37652 closeClick : function(e){
37655 this.fireEvent("beforeclose", this, o);
37656 if(o.cancel !== true){
37657 this.tabPanel.removeTab(this.id);
37661 * The text displayed in the tooltip for the close icon.
37664 closeText : "Close this tab"