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
9095 this.indicator.hide();
9098 this.el.removeClass(this.invalidClass);
9100 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9102 var feedback = this.el.select('.form-control-feedback', true).first();
9105 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9110 this.fireEvent('valid', this);
9114 * Mark this field as valid
9116 markValid : function()
9118 if(!this.el || this.preventMark){ // not rendered...
9122 this.el.removeClass([this.invalidClass, this.validClass]);
9124 var feedback = this.el.select('.form-control-feedback', true).first();
9127 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9134 if(this.allowBlank && !this.getRawValue().length){
9139 this.indicator.hide();
9142 this.el.addClass(this.validClass);
9144 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9146 var feedback = this.el.select('.form-control-feedback', true).first();
9149 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9150 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9155 this.fireEvent('valid', this);
9159 * Mark this field as invalid
9160 * @param {String} msg The validation message
9162 markInvalid : function(msg)
9164 if(!this.el || this.preventMark){ // not rendered
9168 this.el.removeClass([this.invalidClass, this.validClass]);
9170 var feedback = this.el.select('.form-control-feedback', true).first();
9173 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9180 if(this.allowBlank && !this.getRawValue().length){
9185 this.indicator.show();
9188 this.el.addClass(this.invalidClass);
9190 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9192 var feedback = this.el.select('.form-control-feedback', true).first();
9195 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9197 if(this.getValue().length || this.forceFeedback){
9198 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9205 this.fireEvent('invalid', this, msg);
9208 SafariOnKeyDown : function(event)
9210 // this is a workaround for a password hang bug on chrome/ webkit.
9211 if (this.inputEl().dom.type != 'password') {
9215 var isSelectAll = false;
9217 if(this.inputEl().dom.selectionEnd > 0){
9218 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9220 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9221 event.preventDefault();
9226 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9228 event.preventDefault();
9229 // this is very hacky as keydown always get's upper case.
9231 var cc = String.fromCharCode(event.getCharCode());
9232 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9236 adjustWidth : function(tag, w){
9237 tag = tag.toLowerCase();
9238 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9239 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9243 if(tag == 'textarea'){
9246 }else if(Roo.isOpera){
9250 if(tag == 'textarea'){
9269 * @class Roo.bootstrap.TextArea
9270 * @extends Roo.bootstrap.Input
9271 * Bootstrap TextArea class
9272 * @cfg {Number} cols Specifies the visible width of a text area
9273 * @cfg {Number} rows Specifies the visible number of lines in a text area
9274 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9275 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9276 * @cfg {string} html text
9279 * Create a new TextArea
9280 * @param {Object} config The config object
9283 Roo.bootstrap.TextArea = function(config){
9284 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9288 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9298 getAutoCreate : function(){
9300 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9311 value : this.value || '',
9312 html: this.html || '',
9313 cls : 'form-control',
9314 placeholder : this.placeholder || ''
9318 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9319 input.maxLength = this.maxLength;
9323 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9327 input.cols = this.cols;
9330 if (this.readOnly) {
9331 input.readonly = true;
9335 input.name = this.name;
9339 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9343 ['xs','sm','md','lg'].map(function(size){
9344 if (settings[size]) {
9345 cfg.cls += ' col-' + size + '-' + settings[size];
9349 var inputblock = input;
9351 if(this.hasFeedback && !this.allowBlank){
9355 cls: 'glyphicon form-control-feedback'
9359 cls : 'has-feedback',
9368 if (this.before || this.after) {
9371 cls : 'input-group',
9375 inputblock.cn.push({
9377 cls : 'input-group-addon',
9382 inputblock.cn.push(input);
9384 if(this.hasFeedback && !this.allowBlank){
9385 inputblock.cls += ' has-feedback';
9386 inputblock.cn.push(feedback);
9390 inputblock.cn.push({
9392 cls : 'input-group-addon',
9399 if (align ==='left' && this.fieldLabel.length) {
9404 cls : 'control-label',
9405 html : this.fieldLabel
9416 if(this.labelWidth > 12){
9417 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9420 if(this.labelWidth < 13 && this.labelmd == 0){
9421 this.labelmd = this.labelWidth;
9424 if(this.labellg > 0){
9425 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9426 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9429 if(this.labelmd > 0){
9430 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9431 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9434 if(this.labelsm > 0){
9435 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9436 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9439 if(this.labelxs > 0){
9440 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9441 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9444 } else if ( this.fieldLabel.length) {
9449 //cls : 'input-group-addon',
9450 html : this.fieldLabel
9468 if (this.disabled) {
9469 input.disabled=true;
9476 * return the real textarea element.
9478 inputEl: function ()
9480 return this.el.select('textarea.form-control',true).first();
9484 * Clear any invalid styles/messages for this field
9486 clearInvalid : function()
9489 if(!this.el || this.preventMark){ // not rendered
9493 var label = this.el.select('label', true).first();
9494 var icon = this.el.select('i.fa-star', true).first();
9500 this.el.removeClass(this.invalidClass);
9502 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9504 var feedback = this.el.select('.form-control-feedback', true).first();
9507 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9512 this.fireEvent('valid', this);
9516 * Mark this field as valid
9518 markValid : function()
9520 if(!this.el || this.preventMark){ // not rendered
9524 this.el.removeClass([this.invalidClass, this.validClass]);
9526 var feedback = this.el.select('.form-control-feedback', true).first();
9529 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9532 if(this.disabled || this.allowBlank){
9536 var label = this.el.select('label', true).first();
9537 var icon = this.el.select('i.fa-star', true).first();
9543 this.el.addClass(this.validClass);
9545 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9547 var feedback = this.el.select('.form-control-feedback', true).first();
9550 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9551 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9556 this.fireEvent('valid', this);
9560 * Mark this field as invalid
9561 * @param {String} msg The validation message
9563 markInvalid : function(msg)
9565 if(!this.el || this.preventMark){ // not rendered
9569 this.el.removeClass([this.invalidClass, this.validClass]);
9571 var feedback = this.el.select('.form-control-feedback', true).first();
9574 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9577 if(this.disabled || this.allowBlank){
9581 var label = this.el.select('label', true).first();
9582 var icon = this.el.select('i.fa-star', true).first();
9584 if(!this.getValue().length && label && !icon){
9585 this.el.createChild({
9587 cls : 'text-danger fa fa-lg fa-star',
9588 tooltip : 'This field is required',
9589 style : 'margin-right:5px;'
9593 this.el.addClass(this.invalidClass);
9595 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9597 var feedback = this.el.select('.form-control-feedback', true).first();
9600 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9602 if(this.getValue().length || this.forceFeedback){
9603 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9610 this.fireEvent('invalid', this, msg);
9618 * trigger field - base class for combo..
9623 * @class Roo.bootstrap.TriggerField
9624 * @extends Roo.bootstrap.Input
9625 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9626 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9627 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9628 * for which you can provide a custom implementation. For example:
9630 var trigger = new Roo.bootstrap.TriggerField();
9631 trigger.onTriggerClick = myTriggerFn;
9632 trigger.applyTo('my-field');
9635 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9636 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9637 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9638 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9639 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9642 * Create a new TriggerField.
9643 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9644 * to the base TextField)
9646 Roo.bootstrap.TriggerField = function(config){
9647 this.mimicing = false;
9648 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9651 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9653 * @cfg {String} triggerClass A CSS class to apply to the trigger
9656 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9661 * @cfg {Boolean} removable (true|false) special filter default false
9665 /** @cfg {Boolean} grow @hide */
9666 /** @cfg {Number} growMin @hide */
9667 /** @cfg {Number} growMax @hide */
9673 autoSize: Roo.emptyFn,
9680 actionMode : 'wrap',
9685 getAutoCreate : function(){
9687 var align = this.labelAlign || this.parentLabelAlign();
9692 cls: 'form-group' //input-group
9699 type : this.inputType,
9700 cls : 'form-control',
9701 autocomplete: 'new-password',
9702 placeholder : this.placeholder || ''
9706 input.name = this.name;
9709 input.cls += ' input-' + this.size;
9712 if (this.disabled) {
9713 input.disabled=true;
9716 var inputblock = input;
9718 if(this.hasFeedback && !this.allowBlank){
9722 cls: 'glyphicon form-control-feedback'
9725 if(this.removable && !this.editable && !this.tickable){
9727 cls : 'has-feedback',
9733 cls : 'roo-combo-removable-btn close'
9740 cls : 'has-feedback',
9749 if(this.removable && !this.editable && !this.tickable){
9751 cls : 'roo-removable',
9757 cls : 'roo-combo-removable-btn close'
9764 if (this.before || this.after) {
9767 cls : 'input-group',
9771 inputblock.cn.push({
9773 cls : 'input-group-addon',
9778 inputblock.cn.push(input);
9780 if(this.hasFeedback && !this.allowBlank){
9781 inputblock.cls += ' has-feedback';
9782 inputblock.cn.push(feedback);
9786 inputblock.cn.push({
9788 cls : 'input-group-addon',
9801 cls: 'form-hidden-field'
9815 cls: 'form-hidden-field'
9819 cls: 'roo-select2-choices',
9823 cls: 'roo-select2-search-field',
9836 cls: 'roo-select2-container input-group',
9841 // cls: 'typeahead typeahead-long dropdown-menu',
9842 // style: 'display:none'
9847 if(!this.multiple && this.showToggleBtn){
9853 if (this.caret != false) {
9856 cls: 'fa fa-' + this.caret
9863 cls : 'input-group-addon btn dropdown-toggle',
9868 cls: 'combobox-clear',
9882 combobox.cls += ' roo-select2-container-multi';
9885 if (align ==='left' && this.fieldLabel.length) {
9887 cfg.cls += ' roo-form-group-label-left';
9892 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9893 tooltip : 'This field is required'
9898 cls : 'control-label',
9899 html : this.fieldLabel
9911 var labelCfg = cfg.cn[1];
9912 var contentCfg = cfg.cn[2];
9914 if(this.indicatorpos == 'right'){
9919 cls : 'control-label',
9923 html : this.fieldLabel
9927 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9928 tooltip : 'This field is required'
9941 labelCfg = cfg.cn[0];
9942 contentCfg = cfg.cn[1];
9945 if(this.labelWidth > 12){
9946 labelCfg.style = "width: " + this.labelWidth + 'px';
9949 if(this.labelWidth < 13 && this.labelmd == 0){
9950 this.labelmd = this.labelWidth;
9953 if(this.labellg > 0){
9954 labelCfg.cls += ' col-lg-' + this.labellg;
9955 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9958 if(this.labelmd > 0){
9959 labelCfg.cls += ' col-md-' + this.labelmd;
9960 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9963 if(this.labelsm > 0){
9964 labelCfg.cls += ' col-sm-' + this.labelsm;
9965 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9968 if(this.labelxs > 0){
9969 labelCfg.cls += ' col-xs-' + this.labelxs;
9970 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9973 } else if ( this.fieldLabel.length) {
9974 // Roo.log(" label");
9978 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9979 tooltip : 'This field is required'
9983 //cls : 'input-group-addon',
9984 html : this.fieldLabel
9992 if(this.indicatorpos == 'right'){
10000 html : this.fieldLabel
10004 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10005 tooltip : 'This field is required'
10018 // Roo.log(" no label && no align");
10025 ['xs','sm','md','lg'].map(function(size){
10026 if (settings[size]) {
10027 cfg.cls += ' col-' + size + '-' + settings[size];
10038 onResize : function(w, h){
10039 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10040 // if(typeof w == 'number'){
10041 // var x = w - this.trigger.getWidth();
10042 // this.inputEl().setWidth(this.adjustWidth('input', x));
10043 // this.trigger.setStyle('left', x+'px');
10048 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10051 getResizeEl : function(){
10052 return this.inputEl();
10056 getPositionEl : function(){
10057 return this.inputEl();
10061 alignErrorIcon : function(){
10062 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10066 initEvents : function(){
10070 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10071 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10072 if(!this.multiple && this.showToggleBtn){
10073 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10074 if(this.hideTrigger){
10075 this.trigger.setDisplayed(false);
10077 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10081 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10084 if(this.removable && !this.editable && !this.tickable){
10085 var close = this.closeTriggerEl();
10088 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10089 close.on('click', this.removeBtnClick, this, close);
10093 //this.trigger.addClassOnOver('x-form-trigger-over');
10094 //this.trigger.addClassOnClick('x-form-trigger-click');
10097 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10101 closeTriggerEl : function()
10103 var close = this.el.select('.roo-combo-removable-btn', true).first();
10104 return close ? close : false;
10107 removeBtnClick : function(e, h, el)
10109 e.preventDefault();
10111 if(this.fireEvent("remove", this) !== false){
10113 this.fireEvent("afterremove", this)
10117 createList : function()
10119 this.list = Roo.get(document.body).createChild({
10121 cls: 'typeahead typeahead-long dropdown-menu',
10122 style: 'display:none'
10125 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10130 initTrigger : function(){
10135 onDestroy : function(){
10137 this.trigger.removeAllListeners();
10138 // this.trigger.remove();
10141 // this.wrap.remove();
10143 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10147 onFocus : function(){
10148 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10150 if(!this.mimicing){
10151 this.wrap.addClass('x-trigger-wrap-focus');
10152 this.mimicing = true;
10153 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10154 if(this.monitorTab){
10155 this.el.on("keydown", this.checkTab, this);
10162 checkTab : function(e){
10163 if(e.getKey() == e.TAB){
10164 this.triggerBlur();
10169 onBlur : function(){
10174 mimicBlur : function(e, t){
10176 if(!this.wrap.contains(t) && this.validateBlur()){
10177 this.triggerBlur();
10183 triggerBlur : function(){
10184 this.mimicing = false;
10185 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10186 if(this.monitorTab){
10187 this.el.un("keydown", this.checkTab, this);
10189 //this.wrap.removeClass('x-trigger-wrap-focus');
10190 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10194 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10195 validateBlur : function(e, t){
10200 onDisable : function(){
10201 this.inputEl().dom.disabled = true;
10202 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10204 // this.wrap.addClass('x-item-disabled');
10209 onEnable : function(){
10210 this.inputEl().dom.disabled = false;
10211 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10213 // this.el.removeClass('x-item-disabled');
10218 onShow : function(){
10219 var ae = this.getActionEl();
10222 ae.dom.style.display = '';
10223 ae.dom.style.visibility = 'visible';
10229 onHide : function(){
10230 var ae = this.getActionEl();
10231 ae.dom.style.display = 'none';
10235 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10236 * by an implementing function.
10238 * @param {EventObject} e
10240 onTriggerClick : Roo.emptyFn
10244 * Ext JS Library 1.1.1
10245 * Copyright(c) 2006-2007, Ext JS, LLC.
10247 * Originally Released Under LGPL - original licence link has changed is not relivant.
10250 * <script type="text/javascript">
10255 * @class Roo.data.SortTypes
10257 * Defines the default sorting (casting?) comparison functions used when sorting data.
10259 Roo.data.SortTypes = {
10261 * Default sort that does nothing
10262 * @param {Mixed} s The value being converted
10263 * @return {Mixed} The comparison value
10265 none : function(s){
10270 * The regular expression used to strip tags
10274 stripTagsRE : /<\/?[^>]+>/gi,
10277 * Strips all HTML tags to sort on text only
10278 * @param {Mixed} s The value being converted
10279 * @return {String} The comparison value
10281 asText : function(s){
10282 return String(s).replace(this.stripTagsRE, "");
10286 * Strips all HTML tags to sort on text only - Case insensitive
10287 * @param {Mixed} s The value being converted
10288 * @return {String} The comparison value
10290 asUCText : function(s){
10291 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10295 * Case insensitive string
10296 * @param {Mixed} s The value being converted
10297 * @return {String} The comparison value
10299 asUCString : function(s) {
10300 return String(s).toUpperCase();
10305 * @param {Mixed} s The value being converted
10306 * @return {Number} The comparison value
10308 asDate : function(s) {
10312 if(s instanceof Date){
10313 return s.getTime();
10315 return Date.parse(String(s));
10320 * @param {Mixed} s The value being converted
10321 * @return {Float} The comparison value
10323 asFloat : function(s) {
10324 var val = parseFloat(String(s).replace(/,/g, ""));
10333 * @param {Mixed} s The value being converted
10334 * @return {Number} The comparison value
10336 asInt : function(s) {
10337 var val = parseInt(String(s).replace(/,/g, ""));
10345 * Ext JS Library 1.1.1
10346 * Copyright(c) 2006-2007, Ext JS, LLC.
10348 * Originally Released Under LGPL - original licence link has changed is not relivant.
10351 * <script type="text/javascript">
10355 * @class Roo.data.Record
10356 * Instances of this class encapsulate both record <em>definition</em> information, and record
10357 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10358 * to access Records cached in an {@link Roo.data.Store} object.<br>
10360 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10361 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10364 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10366 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10367 * {@link #create}. The parameters are the same.
10368 * @param {Array} data An associative Array of data values keyed by the field name.
10369 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10370 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10371 * not specified an integer id is generated.
10373 Roo.data.Record = function(data, id){
10374 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10379 * Generate a constructor for a specific record layout.
10380 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10381 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10382 * Each field definition object may contain the following properties: <ul>
10383 * <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,
10384 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10385 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10386 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10387 * is being used, then this is a string containing the javascript expression to reference the data relative to
10388 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10389 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10390 * this may be omitted.</p></li>
10391 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10392 * <ul><li>auto (Default, implies no conversion)</li>
10397 * <li>date</li></ul></p></li>
10398 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10399 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10400 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10401 * by the Reader into an object that will be stored in the Record. It is passed the
10402 * following parameters:<ul>
10403 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10405 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10407 * <br>usage:<br><pre><code>
10408 var TopicRecord = Roo.data.Record.create(
10409 {name: 'title', mapping: 'topic_title'},
10410 {name: 'author', mapping: 'username'},
10411 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10412 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10413 {name: 'lastPoster', mapping: 'user2'},
10414 {name: 'excerpt', mapping: 'post_text'}
10417 var myNewRecord = new TopicRecord({
10418 title: 'Do my job please',
10421 lastPost: new Date(),
10422 lastPoster: 'Animal',
10423 excerpt: 'No way dude!'
10425 myStore.add(myNewRecord);
10430 Roo.data.Record.create = function(o){
10431 var f = function(){
10432 f.superclass.constructor.apply(this, arguments);
10434 Roo.extend(f, Roo.data.Record);
10435 var p = f.prototype;
10436 p.fields = new Roo.util.MixedCollection(false, function(field){
10439 for(var i = 0, len = o.length; i < len; i++){
10440 p.fields.add(new Roo.data.Field(o[i]));
10442 f.getField = function(name){
10443 return p.fields.get(name);
10448 Roo.data.Record.AUTO_ID = 1000;
10449 Roo.data.Record.EDIT = 'edit';
10450 Roo.data.Record.REJECT = 'reject';
10451 Roo.data.Record.COMMIT = 'commit';
10453 Roo.data.Record.prototype = {
10455 * Readonly flag - true if this record has been modified.
10464 join : function(store){
10465 this.store = store;
10469 * Set the named field to the specified value.
10470 * @param {String} name The name of the field to set.
10471 * @param {Object} value The value to set the field to.
10473 set : function(name, value){
10474 if(this.data[name] == value){
10478 if(!this.modified){
10479 this.modified = {};
10481 if(typeof this.modified[name] == 'undefined'){
10482 this.modified[name] = this.data[name];
10484 this.data[name] = value;
10485 if(!this.editing && this.store){
10486 this.store.afterEdit(this);
10491 * Get the value of the named field.
10492 * @param {String} name The name of the field to get the value of.
10493 * @return {Object} The value of the field.
10495 get : function(name){
10496 return this.data[name];
10500 beginEdit : function(){
10501 this.editing = true;
10502 this.modified = {};
10506 cancelEdit : function(){
10507 this.editing = false;
10508 delete this.modified;
10512 endEdit : function(){
10513 this.editing = false;
10514 if(this.dirty && this.store){
10515 this.store.afterEdit(this);
10520 * Usually called by the {@link Roo.data.Store} which owns the Record.
10521 * Rejects all changes made to the Record since either creation, or the last commit operation.
10522 * Modified fields are reverted to their original values.
10524 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10525 * of reject operations.
10527 reject : function(){
10528 var m = this.modified;
10530 if(typeof m[n] != "function"){
10531 this.data[n] = m[n];
10534 this.dirty = false;
10535 delete this.modified;
10536 this.editing = false;
10538 this.store.afterReject(this);
10543 * Usually called by the {@link Roo.data.Store} which owns the Record.
10544 * Commits all changes made to the Record since either creation, or the last commit operation.
10546 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10547 * of commit operations.
10549 commit : function(){
10550 this.dirty = false;
10551 delete this.modified;
10552 this.editing = false;
10554 this.store.afterCommit(this);
10559 hasError : function(){
10560 return this.error != null;
10564 clearError : function(){
10569 * Creates a copy of this record.
10570 * @param {String} id (optional) A new record id if you don't want to use this record's id
10573 copy : function(newId) {
10574 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10578 * Ext JS Library 1.1.1
10579 * Copyright(c) 2006-2007, Ext JS, LLC.
10581 * Originally Released Under LGPL - original licence link has changed is not relivant.
10584 * <script type="text/javascript">
10590 * @class Roo.data.Store
10591 * @extends Roo.util.Observable
10592 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10593 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10595 * 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
10596 * has no knowledge of the format of the data returned by the Proxy.<br>
10598 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10599 * instances from the data object. These records are cached and made available through accessor functions.
10601 * Creates a new Store.
10602 * @param {Object} config A config object containing the objects needed for the Store to access data,
10603 * and read the data into Records.
10605 Roo.data.Store = function(config){
10606 this.data = new Roo.util.MixedCollection(false);
10607 this.data.getKey = function(o){
10610 this.baseParams = {};
10612 this.paramNames = {
10617 "multisort" : "_multisort"
10620 if(config && config.data){
10621 this.inlineData = config.data;
10622 delete config.data;
10625 Roo.apply(this, config);
10627 if(this.reader){ // reader passed
10628 this.reader = Roo.factory(this.reader, Roo.data);
10629 this.reader.xmodule = this.xmodule || false;
10630 if(!this.recordType){
10631 this.recordType = this.reader.recordType;
10633 if(this.reader.onMetaChange){
10634 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10638 if(this.recordType){
10639 this.fields = this.recordType.prototype.fields;
10641 this.modified = [];
10645 * @event datachanged
10646 * Fires when the data cache has changed, and a widget which is using this Store
10647 * as a Record cache should refresh its view.
10648 * @param {Store} this
10650 datachanged : true,
10652 * @event metachange
10653 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10654 * @param {Store} this
10655 * @param {Object} meta The JSON metadata
10660 * Fires when Records have been added to the Store
10661 * @param {Store} this
10662 * @param {Roo.data.Record[]} records The array of Records added
10663 * @param {Number} index The index at which the record(s) were added
10668 * Fires when a Record has been removed from the Store
10669 * @param {Store} this
10670 * @param {Roo.data.Record} record The Record that was removed
10671 * @param {Number} index The index at which the record was removed
10676 * Fires when a Record has been updated
10677 * @param {Store} this
10678 * @param {Roo.data.Record} record The Record that was updated
10679 * @param {String} operation The update operation being performed. Value may be one of:
10681 Roo.data.Record.EDIT
10682 Roo.data.Record.REJECT
10683 Roo.data.Record.COMMIT
10689 * Fires when the data cache has been cleared.
10690 * @param {Store} this
10694 * @event beforeload
10695 * Fires before a request is made for a new data object. If the beforeload handler returns false
10696 * the load action will be canceled.
10697 * @param {Store} this
10698 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10702 * @event beforeloadadd
10703 * Fires after a new set of Records has been loaded.
10704 * @param {Store} this
10705 * @param {Roo.data.Record[]} records The Records that were loaded
10706 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10708 beforeloadadd : true,
10711 * Fires after a new set of Records has been loaded, before they are added to the store.
10712 * @param {Store} this
10713 * @param {Roo.data.Record[]} records The Records that were loaded
10714 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10715 * @params {Object} return from reader
10719 * @event loadexception
10720 * Fires if an exception occurs in the Proxy during loading.
10721 * Called with the signature of the Proxy's "loadexception" event.
10722 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10725 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10726 * @param {Object} load options
10727 * @param {Object} jsonData from your request (normally this contains the Exception)
10729 loadexception : true
10733 this.proxy = Roo.factory(this.proxy, Roo.data);
10734 this.proxy.xmodule = this.xmodule || false;
10735 this.relayEvents(this.proxy, ["loadexception"]);
10737 this.sortToggle = {};
10738 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10740 Roo.data.Store.superclass.constructor.call(this);
10742 if(this.inlineData){
10743 this.loadData(this.inlineData);
10744 delete this.inlineData;
10748 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10750 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10751 * without a remote query - used by combo/forms at present.
10755 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10758 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10761 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10762 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10765 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10766 * on any HTTP request
10769 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10772 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10776 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10777 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10779 remoteSort : false,
10782 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10783 * loaded or when a record is removed. (defaults to false).
10785 pruneModifiedRecords : false,
10788 lastOptions : null,
10791 * Add Records to the Store and fires the add event.
10792 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10794 add : function(records){
10795 records = [].concat(records);
10796 for(var i = 0, len = records.length; i < len; i++){
10797 records[i].join(this);
10799 var index = this.data.length;
10800 this.data.addAll(records);
10801 this.fireEvent("add", this, records, index);
10805 * Remove a Record from the Store and fires the remove event.
10806 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10808 remove : function(record){
10809 var index = this.data.indexOf(record);
10810 this.data.removeAt(index);
10811 if(this.pruneModifiedRecords){
10812 this.modified.remove(record);
10814 this.fireEvent("remove", this, record, index);
10818 * Remove all Records from the Store and fires the clear event.
10820 removeAll : function(){
10822 if(this.pruneModifiedRecords){
10823 this.modified = [];
10825 this.fireEvent("clear", this);
10829 * Inserts Records to the Store at the given index and fires the add event.
10830 * @param {Number} index The start index at which to insert the passed Records.
10831 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10833 insert : function(index, records){
10834 records = [].concat(records);
10835 for(var i = 0, len = records.length; i < len; i++){
10836 this.data.insert(index, records[i]);
10837 records[i].join(this);
10839 this.fireEvent("add", this, records, index);
10843 * Get the index within the cache of the passed Record.
10844 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10845 * @return {Number} The index of the passed Record. Returns -1 if not found.
10847 indexOf : function(record){
10848 return this.data.indexOf(record);
10852 * Get the index within the cache of the Record with the passed id.
10853 * @param {String} id The id of the Record to find.
10854 * @return {Number} The index of the Record. Returns -1 if not found.
10856 indexOfId : function(id){
10857 return this.data.indexOfKey(id);
10861 * Get the Record with the specified id.
10862 * @param {String} id The id of the Record to find.
10863 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10865 getById : function(id){
10866 return this.data.key(id);
10870 * Get the Record at the specified index.
10871 * @param {Number} index The index of the Record to find.
10872 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10874 getAt : function(index){
10875 return this.data.itemAt(index);
10879 * Returns a range of Records between specified indices.
10880 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10881 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10882 * @return {Roo.data.Record[]} An array of Records
10884 getRange : function(start, end){
10885 return this.data.getRange(start, end);
10889 storeOptions : function(o){
10890 o = Roo.apply({}, o);
10893 this.lastOptions = o;
10897 * Loads the Record cache from the configured Proxy using the configured Reader.
10899 * If using remote paging, then the first load call must specify the <em>start</em>
10900 * and <em>limit</em> properties in the options.params property to establish the initial
10901 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10903 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10904 * and this call will return before the new data has been loaded. Perform any post-processing
10905 * in a callback function, or in a "load" event handler.</strong>
10907 * @param {Object} options An object containing properties which control loading options:<ul>
10908 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10909 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10910 * passed the following arguments:<ul>
10911 * <li>r : Roo.data.Record[]</li>
10912 * <li>options: Options object from the load call</li>
10913 * <li>success: Boolean success indicator</li></ul></li>
10914 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10915 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10918 load : function(options){
10919 options = options || {};
10920 if(this.fireEvent("beforeload", this, options) !== false){
10921 this.storeOptions(options);
10922 var p = Roo.apply(options.params || {}, this.baseParams);
10923 // if meta was not loaded from remote source.. try requesting it.
10924 if (!this.reader.metaFromRemote) {
10925 p._requestMeta = 1;
10927 if(this.sortInfo && this.remoteSort){
10928 var pn = this.paramNames;
10929 p[pn["sort"]] = this.sortInfo.field;
10930 p[pn["dir"]] = this.sortInfo.direction;
10932 if (this.multiSort) {
10933 var pn = this.paramNames;
10934 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10937 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10942 * Reloads the Record cache from the configured Proxy using the configured Reader and
10943 * the options from the last load operation performed.
10944 * @param {Object} options (optional) An object containing properties which may override the options
10945 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10946 * the most recently used options are reused).
10948 reload : function(options){
10949 this.load(Roo.applyIf(options||{}, this.lastOptions));
10953 // Called as a callback by the Reader during a load operation.
10954 loadRecords : function(o, options, success){
10955 if(!o || success === false){
10956 if(success !== false){
10957 this.fireEvent("load", this, [], options, o);
10959 if(options.callback){
10960 options.callback.call(options.scope || this, [], options, false);
10964 // if data returned failure - throw an exception.
10965 if (o.success === false) {
10966 // show a message if no listener is registered.
10967 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10968 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10970 // loadmask wil be hooked into this..
10971 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10974 var r = o.records, t = o.totalRecords || r.length;
10976 this.fireEvent("beforeloadadd", this, r, options, o);
10978 if(!options || options.add !== true){
10979 if(this.pruneModifiedRecords){
10980 this.modified = [];
10982 for(var i = 0, len = r.length; i < len; i++){
10986 this.data = this.snapshot;
10987 delete this.snapshot;
10990 this.data.addAll(r);
10991 this.totalLength = t;
10993 this.fireEvent("datachanged", this);
10995 this.totalLength = Math.max(t, this.data.length+r.length);
10998 this.fireEvent("load", this, r, options, o);
10999 if(options.callback){
11000 options.callback.call(options.scope || this, r, options, true);
11006 * Loads data from a passed data block. A Reader which understands the format of the data
11007 * must have been configured in the constructor.
11008 * @param {Object} data The data block from which to read the Records. The format of the data expected
11009 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11010 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11012 loadData : function(o, append){
11013 var r = this.reader.readRecords(o);
11014 this.loadRecords(r, {add: append}, true);
11018 * Gets the number of cached records.
11020 * <em>If using paging, this may not be the total size of the dataset. If the data object
11021 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11022 * the data set size</em>
11024 getCount : function(){
11025 return this.data.length || 0;
11029 * Gets the total number of records in the dataset as returned by the server.
11031 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11032 * the dataset size</em>
11034 getTotalCount : function(){
11035 return this.totalLength || 0;
11039 * Returns the sort state of the Store as an object with two properties:
11041 field {String} The name of the field by which the Records are sorted
11042 direction {String} The sort order, "ASC" or "DESC"
11045 getSortState : function(){
11046 return this.sortInfo;
11050 applySort : function(){
11051 if(this.sortInfo && !this.remoteSort){
11052 var s = this.sortInfo, f = s.field;
11053 var st = this.fields.get(f).sortType;
11054 var fn = function(r1, r2){
11055 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11056 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11058 this.data.sort(s.direction, fn);
11059 if(this.snapshot && this.snapshot != this.data){
11060 this.snapshot.sort(s.direction, fn);
11066 * Sets the default sort column and order to be used by the next load operation.
11067 * @param {String} fieldName The name of the field to sort by.
11068 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11070 setDefaultSort : function(field, dir){
11071 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11075 * Sort the Records.
11076 * If remote sorting is used, the sort is performed on the server, and the cache is
11077 * reloaded. If local sorting is used, the cache is sorted internally.
11078 * @param {String} fieldName The name of the field to sort by.
11079 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11081 sort : function(fieldName, dir){
11082 var f = this.fields.get(fieldName);
11084 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11086 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11087 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11092 this.sortToggle[f.name] = dir;
11093 this.sortInfo = {field: f.name, direction: dir};
11094 if(!this.remoteSort){
11096 this.fireEvent("datachanged", this);
11098 this.load(this.lastOptions);
11103 * Calls the specified function for each of the Records in the cache.
11104 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11105 * Returning <em>false</em> aborts and exits the iteration.
11106 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11108 each : function(fn, scope){
11109 this.data.each(fn, scope);
11113 * Gets all records modified since the last commit. Modified records are persisted across load operations
11114 * (e.g., during paging).
11115 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11117 getModifiedRecords : function(){
11118 return this.modified;
11122 createFilterFn : function(property, value, anyMatch){
11123 if(!value.exec){ // not a regex
11124 value = String(value);
11125 if(value.length == 0){
11128 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11130 return function(r){
11131 return value.test(r.data[property]);
11136 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11137 * @param {String} property A field on your records
11138 * @param {Number} start The record index to start at (defaults to 0)
11139 * @param {Number} end The last record index to include (defaults to length - 1)
11140 * @return {Number} The sum
11142 sum : function(property, start, end){
11143 var rs = this.data.items, v = 0;
11144 start = start || 0;
11145 end = (end || end === 0) ? end : rs.length-1;
11147 for(var i = start; i <= end; i++){
11148 v += (rs[i].data[property] || 0);
11154 * Filter the records by a specified property.
11155 * @param {String} field A field on your records
11156 * @param {String/RegExp} value Either a string that the field
11157 * should start with or a RegExp to test against the field
11158 * @param {Boolean} anyMatch True to match any part not just the beginning
11160 filter : function(property, value, anyMatch){
11161 var fn = this.createFilterFn(property, value, anyMatch);
11162 return fn ? this.filterBy(fn) : this.clearFilter();
11166 * Filter by a function. The specified function will be called with each
11167 * record in this data source. If the function returns true the record is included,
11168 * otherwise it is filtered.
11169 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11170 * @param {Object} scope (optional) The scope of the function (defaults to this)
11172 filterBy : function(fn, scope){
11173 this.snapshot = this.snapshot || this.data;
11174 this.data = this.queryBy(fn, scope||this);
11175 this.fireEvent("datachanged", this);
11179 * Query the records by a specified property.
11180 * @param {String} field A field on your records
11181 * @param {String/RegExp} value Either a string that the field
11182 * should start with or a RegExp to test against the field
11183 * @param {Boolean} anyMatch True to match any part not just the beginning
11184 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11186 query : function(property, value, anyMatch){
11187 var fn = this.createFilterFn(property, value, anyMatch);
11188 return fn ? this.queryBy(fn) : this.data.clone();
11192 * Query by a function. The specified function will be called with each
11193 * record in this data source. If the function returns true the record is included
11195 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11196 * @param {Object} scope (optional) The scope of the function (defaults to this)
11197 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11199 queryBy : function(fn, scope){
11200 var data = this.snapshot || this.data;
11201 return data.filterBy(fn, scope||this);
11205 * Collects unique values for a particular dataIndex from this store.
11206 * @param {String} dataIndex The property to collect
11207 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11208 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11209 * @return {Array} An array of the unique values
11211 collect : function(dataIndex, allowNull, bypassFilter){
11212 var d = (bypassFilter === true && this.snapshot) ?
11213 this.snapshot.items : this.data.items;
11214 var v, sv, r = [], l = {};
11215 for(var i = 0, len = d.length; i < len; i++){
11216 v = d[i].data[dataIndex];
11218 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11227 * Revert to a view of the Record cache with no filtering applied.
11228 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11230 clearFilter : function(suppressEvent){
11231 if(this.snapshot && this.snapshot != this.data){
11232 this.data = this.snapshot;
11233 delete this.snapshot;
11234 if(suppressEvent !== true){
11235 this.fireEvent("datachanged", this);
11241 afterEdit : function(record){
11242 if(this.modified.indexOf(record) == -1){
11243 this.modified.push(record);
11245 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11249 afterReject : function(record){
11250 this.modified.remove(record);
11251 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11255 afterCommit : function(record){
11256 this.modified.remove(record);
11257 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11261 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11262 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11264 commitChanges : function(){
11265 var m = this.modified.slice(0);
11266 this.modified = [];
11267 for(var i = 0, len = m.length; i < len; i++){
11273 * Cancel outstanding changes on all changed records.
11275 rejectChanges : function(){
11276 var m = this.modified.slice(0);
11277 this.modified = [];
11278 for(var i = 0, len = m.length; i < len; i++){
11283 onMetaChange : function(meta, rtype, o){
11284 this.recordType = rtype;
11285 this.fields = rtype.prototype.fields;
11286 delete this.snapshot;
11287 this.sortInfo = meta.sortInfo || this.sortInfo;
11288 this.modified = [];
11289 this.fireEvent('metachange', this, this.reader.meta);
11292 moveIndex : function(data, type)
11294 var index = this.indexOf(data);
11296 var newIndex = index + type;
11300 this.insert(newIndex, data);
11305 * Ext JS Library 1.1.1
11306 * Copyright(c) 2006-2007, Ext JS, LLC.
11308 * Originally Released Under LGPL - original licence link has changed is not relivant.
11311 * <script type="text/javascript">
11315 * @class Roo.data.SimpleStore
11316 * @extends Roo.data.Store
11317 * Small helper class to make creating Stores from Array data easier.
11318 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11319 * @cfg {Array} fields An array of field definition objects, or field name strings.
11320 * @cfg {Array} data The multi-dimensional array of data
11322 * @param {Object} config
11324 Roo.data.SimpleStore = function(config){
11325 Roo.data.SimpleStore.superclass.constructor.call(this, {
11327 reader: new Roo.data.ArrayReader({
11330 Roo.data.Record.create(config.fields)
11332 proxy : new Roo.data.MemoryProxy(config.data)
11336 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11338 * Ext JS Library 1.1.1
11339 * Copyright(c) 2006-2007, Ext JS, LLC.
11341 * Originally Released Under LGPL - original licence link has changed is not relivant.
11344 * <script type="text/javascript">
11349 * @extends Roo.data.Store
11350 * @class Roo.data.JsonStore
11351 * Small helper class to make creating Stores for JSON data easier. <br/>
11353 var store = new Roo.data.JsonStore({
11354 url: 'get-images.php',
11356 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11359 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11360 * JsonReader and HttpProxy (unless inline data is provided).</b>
11361 * @cfg {Array} fields An array of field definition objects, or field name strings.
11363 * @param {Object} config
11365 Roo.data.JsonStore = function(c){
11366 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11367 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11368 reader: new Roo.data.JsonReader(c, c.fields)
11371 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11373 * Ext JS Library 1.1.1
11374 * Copyright(c) 2006-2007, Ext JS, LLC.
11376 * Originally Released Under LGPL - original licence link has changed is not relivant.
11379 * <script type="text/javascript">
11383 Roo.data.Field = function(config){
11384 if(typeof config == "string"){
11385 config = {name: config};
11387 Roo.apply(this, config);
11390 this.type = "auto";
11393 var st = Roo.data.SortTypes;
11394 // named sortTypes are supported, here we look them up
11395 if(typeof this.sortType == "string"){
11396 this.sortType = st[this.sortType];
11399 // set default sortType for strings and dates
11400 if(!this.sortType){
11403 this.sortType = st.asUCString;
11406 this.sortType = st.asDate;
11409 this.sortType = st.none;
11414 var stripRe = /[\$,%]/g;
11416 // prebuilt conversion function for this field, instead of
11417 // switching every time we're reading a value
11419 var cv, dateFormat = this.dateFormat;
11424 cv = function(v){ return v; };
11427 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11431 return v !== undefined && v !== null && v !== '' ?
11432 parseInt(String(v).replace(stripRe, ""), 10) : '';
11437 return v !== undefined && v !== null && v !== '' ?
11438 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11443 cv = function(v){ return v === true || v === "true" || v == 1; };
11450 if(v instanceof Date){
11454 if(dateFormat == "timestamp"){
11455 return new Date(v*1000);
11457 return Date.parseDate(v, dateFormat);
11459 var parsed = Date.parse(v);
11460 return parsed ? new Date(parsed) : null;
11469 Roo.data.Field.prototype = {
11477 * Ext JS Library 1.1.1
11478 * Copyright(c) 2006-2007, Ext JS, LLC.
11480 * Originally Released Under LGPL - original licence link has changed is not relivant.
11483 * <script type="text/javascript">
11486 // Base class for reading structured data from a data source. This class is intended to be
11487 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11490 * @class Roo.data.DataReader
11491 * Base class for reading structured data from a data source. This class is intended to be
11492 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11495 Roo.data.DataReader = function(meta, recordType){
11499 this.recordType = recordType instanceof Array ?
11500 Roo.data.Record.create(recordType) : recordType;
11503 Roo.data.DataReader.prototype = {
11505 * Create an empty record
11506 * @param {Object} data (optional) - overlay some values
11507 * @return {Roo.data.Record} record created.
11509 newRow : function(d) {
11511 this.recordType.prototype.fields.each(function(c) {
11513 case 'int' : da[c.name] = 0; break;
11514 case 'date' : da[c.name] = new Date(); break;
11515 case 'float' : da[c.name] = 0.0; break;
11516 case 'boolean' : da[c.name] = false; break;
11517 default : da[c.name] = ""; break;
11521 return new this.recordType(Roo.apply(da, d));
11526 * Ext JS Library 1.1.1
11527 * Copyright(c) 2006-2007, Ext JS, LLC.
11529 * Originally Released Under LGPL - original licence link has changed is not relivant.
11532 * <script type="text/javascript">
11536 * @class Roo.data.DataProxy
11537 * @extends Roo.data.Observable
11538 * This class is an abstract base class for implementations which provide retrieval of
11539 * unformatted data objects.<br>
11541 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11542 * (of the appropriate type which knows how to parse the data object) to provide a block of
11543 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11545 * Custom implementations must implement the load method as described in
11546 * {@link Roo.data.HttpProxy#load}.
11548 Roo.data.DataProxy = function(){
11551 * @event beforeload
11552 * Fires before a network request is made to retrieve a data object.
11553 * @param {Object} This DataProxy object.
11554 * @param {Object} params The params parameter to the load function.
11559 * Fires before the load method's callback is called.
11560 * @param {Object} This DataProxy object.
11561 * @param {Object} o The data object.
11562 * @param {Object} arg The callback argument object passed to the load function.
11566 * @event loadexception
11567 * Fires if an Exception occurs during data retrieval.
11568 * @param {Object} This DataProxy object.
11569 * @param {Object} o The data object.
11570 * @param {Object} arg The callback argument object passed to the load function.
11571 * @param {Object} e The Exception.
11573 loadexception : true
11575 Roo.data.DataProxy.superclass.constructor.call(this);
11578 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11581 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11585 * Ext JS Library 1.1.1
11586 * Copyright(c) 2006-2007, Ext JS, LLC.
11588 * Originally Released Under LGPL - original licence link has changed is not relivant.
11591 * <script type="text/javascript">
11594 * @class Roo.data.MemoryProxy
11595 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11596 * to the Reader when its load method is called.
11598 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11600 Roo.data.MemoryProxy = function(data){
11604 Roo.data.MemoryProxy.superclass.constructor.call(this);
11608 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11611 * Load data from the requested source (in this case an in-memory
11612 * data object passed to the constructor), read the data object into
11613 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11614 * process that block using the passed callback.
11615 * @param {Object} params This parameter is not used by the MemoryProxy class.
11616 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11617 * object into a block of Roo.data.Records.
11618 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11619 * The function must be passed <ul>
11620 * <li>The Record block object</li>
11621 * <li>The "arg" argument from the load function</li>
11622 * <li>A boolean success indicator</li>
11624 * @param {Object} scope The scope in which to call the callback
11625 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11627 load : function(params, reader, callback, scope, arg){
11628 params = params || {};
11631 result = reader.readRecords(this.data);
11633 this.fireEvent("loadexception", this, arg, null, e);
11634 callback.call(scope, null, arg, false);
11637 callback.call(scope, result, arg, true);
11641 update : function(params, records){
11646 * Ext JS Library 1.1.1
11647 * Copyright(c) 2006-2007, Ext JS, LLC.
11649 * Originally Released Under LGPL - original licence link has changed is not relivant.
11652 * <script type="text/javascript">
11655 * @class Roo.data.HttpProxy
11656 * @extends Roo.data.DataProxy
11657 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11658 * configured to reference a certain URL.<br><br>
11660 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11661 * from which the running page was served.<br><br>
11663 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11665 * Be aware that to enable the browser to parse an XML document, the server must set
11666 * the Content-Type header in the HTTP response to "text/xml".
11668 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11669 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11670 * will be used to make the request.
11672 Roo.data.HttpProxy = function(conn){
11673 Roo.data.HttpProxy.superclass.constructor.call(this);
11674 // is conn a conn config or a real conn?
11676 this.useAjax = !conn || !conn.events;
11680 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11681 // thse are take from connection...
11684 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11687 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11688 * extra parameters to each request made by this object. (defaults to undefined)
11691 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11692 * to each request made by this object. (defaults to undefined)
11695 * @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)
11698 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11701 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11707 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11711 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11712 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11713 * a finer-grained basis than the DataProxy events.
11715 getConnection : function(){
11716 return this.useAjax ? Roo.Ajax : this.conn;
11720 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11721 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11722 * process that block using the passed callback.
11723 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11724 * for the request to the remote server.
11725 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11726 * object into a block of Roo.data.Records.
11727 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11728 * The function must be passed <ul>
11729 * <li>The Record block object</li>
11730 * <li>The "arg" argument from the load function</li>
11731 * <li>A boolean success indicator</li>
11733 * @param {Object} scope The scope in which to call the callback
11734 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11736 load : function(params, reader, callback, scope, arg){
11737 if(this.fireEvent("beforeload", this, params) !== false){
11739 params : params || {},
11741 callback : callback,
11746 callback : this.loadResponse,
11750 Roo.applyIf(o, this.conn);
11751 if(this.activeRequest){
11752 Roo.Ajax.abort(this.activeRequest);
11754 this.activeRequest = Roo.Ajax.request(o);
11756 this.conn.request(o);
11759 callback.call(scope||this, null, arg, false);
11764 loadResponse : function(o, success, response){
11765 delete this.activeRequest;
11767 this.fireEvent("loadexception", this, o, response);
11768 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11773 result = o.reader.read(response);
11775 this.fireEvent("loadexception", this, o, response, e);
11776 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11780 this.fireEvent("load", this, o, o.request.arg);
11781 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11785 update : function(dataSet){
11790 updateResponse : function(dataSet){
11795 * Ext JS Library 1.1.1
11796 * Copyright(c) 2006-2007, Ext JS, LLC.
11798 * Originally Released Under LGPL - original licence link has changed is not relivant.
11801 * <script type="text/javascript">
11805 * @class Roo.data.ScriptTagProxy
11806 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11807 * other than the originating domain of the running page.<br><br>
11809 * <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
11810 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11812 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11813 * source code that is used as the source inside a <script> tag.<br><br>
11815 * In order for the browser to process the returned data, the server must wrap the data object
11816 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11817 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11818 * depending on whether the callback name was passed:
11821 boolean scriptTag = false;
11822 String cb = request.getParameter("callback");
11825 response.setContentType("text/javascript");
11827 response.setContentType("application/x-json");
11829 Writer out = response.getWriter();
11831 out.write(cb + "(");
11833 out.print(dataBlock.toJsonString());
11840 * @param {Object} config A configuration object.
11842 Roo.data.ScriptTagProxy = function(config){
11843 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11844 Roo.apply(this, config);
11845 this.head = document.getElementsByTagName("head")[0];
11848 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11850 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11852 * @cfg {String} url The URL from which to request the data object.
11855 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11859 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11860 * the server the name of the callback function set up by the load call to process the returned data object.
11861 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11862 * javascript output which calls this named function passing the data object as its only parameter.
11864 callbackParam : "callback",
11866 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11867 * name to the request.
11872 * Load data from the configured URL, read the data object into
11873 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11874 * process that block using the passed callback.
11875 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11876 * for the request to the remote server.
11877 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11878 * object into a block of Roo.data.Records.
11879 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11880 * The function must be passed <ul>
11881 * <li>The Record block object</li>
11882 * <li>The "arg" argument from the load function</li>
11883 * <li>A boolean success indicator</li>
11885 * @param {Object} scope The scope in which to call the callback
11886 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11888 load : function(params, reader, callback, scope, arg){
11889 if(this.fireEvent("beforeload", this, params) !== false){
11891 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11893 var url = this.url;
11894 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11896 url += "&_dc=" + (new Date().getTime());
11898 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11901 cb : "stcCallback"+transId,
11902 scriptId : "stcScript"+transId,
11906 callback : callback,
11912 window[trans.cb] = function(o){
11913 conn.handleResponse(o, trans);
11916 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11918 if(this.autoAbort !== false){
11922 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11924 var script = document.createElement("script");
11925 script.setAttribute("src", url);
11926 script.setAttribute("type", "text/javascript");
11927 script.setAttribute("id", trans.scriptId);
11928 this.head.appendChild(script);
11930 this.trans = trans;
11932 callback.call(scope||this, null, arg, false);
11937 isLoading : function(){
11938 return this.trans ? true : false;
11942 * Abort the current server request.
11944 abort : function(){
11945 if(this.isLoading()){
11946 this.destroyTrans(this.trans);
11951 destroyTrans : function(trans, isLoaded){
11952 this.head.removeChild(document.getElementById(trans.scriptId));
11953 clearTimeout(trans.timeoutId);
11955 window[trans.cb] = undefined;
11957 delete window[trans.cb];
11960 // if hasn't been loaded, wait for load to remove it to prevent script error
11961 window[trans.cb] = function(){
11962 window[trans.cb] = undefined;
11964 delete window[trans.cb];
11971 handleResponse : function(o, trans){
11972 this.trans = false;
11973 this.destroyTrans(trans, true);
11976 result = trans.reader.readRecords(o);
11978 this.fireEvent("loadexception", this, o, trans.arg, e);
11979 trans.callback.call(trans.scope||window, null, trans.arg, false);
11982 this.fireEvent("load", this, o, trans.arg);
11983 trans.callback.call(trans.scope||window, result, trans.arg, true);
11987 handleFailure : function(trans){
11988 this.trans = false;
11989 this.destroyTrans(trans, false);
11990 this.fireEvent("loadexception", this, null, trans.arg);
11991 trans.callback.call(trans.scope||window, null, trans.arg, false);
11995 * Ext JS Library 1.1.1
11996 * Copyright(c) 2006-2007, Ext JS, LLC.
11998 * Originally Released Under LGPL - original licence link has changed is not relivant.
12001 * <script type="text/javascript">
12005 * @class Roo.data.JsonReader
12006 * @extends Roo.data.DataReader
12007 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12008 * based on mappings in a provided Roo.data.Record constructor.
12010 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12011 * in the reply previously.
12016 var RecordDef = Roo.data.Record.create([
12017 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12018 {name: 'occupation'} // This field will use "occupation" as the mapping.
12020 var myReader = new Roo.data.JsonReader({
12021 totalProperty: "results", // The property which contains the total dataset size (optional)
12022 root: "rows", // The property which contains an Array of row objects
12023 id: "id" // The property within each row object that provides an ID for the record (optional)
12027 * This would consume a JSON file like this:
12029 { 'results': 2, 'rows': [
12030 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12031 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12034 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12035 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12036 * paged from the remote server.
12037 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12038 * @cfg {String} root name of the property which contains the Array of row objects.
12039 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12040 * @cfg {Array} fields Array of field definition objects
12042 * Create a new JsonReader
12043 * @param {Object} meta Metadata configuration options
12044 * @param {Object} recordType Either an Array of field definition objects,
12045 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12047 Roo.data.JsonReader = function(meta, recordType){
12050 // set some defaults:
12051 Roo.applyIf(meta, {
12052 totalProperty: 'total',
12053 successProperty : 'success',
12058 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12060 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12063 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12064 * Used by Store query builder to append _requestMeta to params.
12067 metaFromRemote : false,
12069 * This method is only used by a DataProxy which has retrieved data from a remote server.
12070 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12071 * @return {Object} data A data block which is used by an Roo.data.Store object as
12072 * a cache of Roo.data.Records.
12074 read : function(response){
12075 var json = response.responseText;
12077 var o = /* eval:var:o */ eval("("+json+")");
12079 throw {message: "JsonReader.read: Json object not found"};
12085 this.metaFromRemote = true;
12086 this.meta = o.metaData;
12087 this.recordType = Roo.data.Record.create(o.metaData.fields);
12088 this.onMetaChange(this.meta, this.recordType, o);
12090 return this.readRecords(o);
12093 // private function a store will implement
12094 onMetaChange : function(meta, recordType, o){
12101 simpleAccess: function(obj, subsc) {
12108 getJsonAccessor: function(){
12110 return function(expr) {
12112 return(re.test(expr))
12113 ? new Function("obj", "return obj." + expr)
12118 return Roo.emptyFn;
12123 * Create a data block containing Roo.data.Records from an XML document.
12124 * @param {Object} o An object which contains an Array of row objects in the property specified
12125 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12126 * which contains the total size of the dataset.
12127 * @return {Object} data A data block which is used by an Roo.data.Store object as
12128 * a cache of Roo.data.Records.
12130 readRecords : function(o){
12132 * After any data loads, the raw JSON data is available for further custom processing.
12136 var s = this.meta, Record = this.recordType,
12137 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12139 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12141 if(s.totalProperty) {
12142 this.getTotal = this.getJsonAccessor(s.totalProperty);
12144 if(s.successProperty) {
12145 this.getSuccess = this.getJsonAccessor(s.successProperty);
12147 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12149 var g = this.getJsonAccessor(s.id);
12150 this.getId = function(rec) {
12152 return (r === undefined || r === "") ? null : r;
12155 this.getId = function(){return null;};
12158 for(var jj = 0; jj < fl; jj++){
12160 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12161 this.ef[jj] = this.getJsonAccessor(map);
12165 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12166 if(s.totalProperty){
12167 var vt = parseInt(this.getTotal(o), 10);
12172 if(s.successProperty){
12173 var vs = this.getSuccess(o);
12174 if(vs === false || vs === 'false'){
12179 for(var i = 0; i < c; i++){
12182 var id = this.getId(n);
12183 for(var j = 0; j < fl; j++){
12185 var v = this.ef[j](n);
12187 Roo.log('missing convert for ' + f.name);
12191 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12193 var record = new Record(values, id);
12195 records[i] = record;
12201 totalRecords : totalRecords
12206 * Ext JS Library 1.1.1
12207 * Copyright(c) 2006-2007, Ext JS, LLC.
12209 * Originally Released Under LGPL - original licence link has changed is not relivant.
12212 * <script type="text/javascript">
12216 * @class Roo.data.ArrayReader
12217 * @extends Roo.data.DataReader
12218 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12219 * Each element of that Array represents a row of data fields. The
12220 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12221 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12225 var RecordDef = Roo.data.Record.create([
12226 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12227 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12229 var myReader = new Roo.data.ArrayReader({
12230 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12234 * This would consume an Array like this:
12236 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12238 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12240 * Create a new JsonReader
12241 * @param {Object} meta Metadata configuration options.
12242 * @param {Object} recordType Either an Array of field definition objects
12243 * as specified to {@link Roo.data.Record#create},
12244 * or an {@link Roo.data.Record} object
12245 * created using {@link Roo.data.Record#create}.
12247 Roo.data.ArrayReader = function(meta, recordType){
12248 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12251 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12253 * Create a data block containing Roo.data.Records from an XML document.
12254 * @param {Object} o An Array of row objects which represents the dataset.
12255 * @return {Object} data A data block which is used by an Roo.data.Store object as
12256 * a cache of Roo.data.Records.
12258 readRecords : function(o){
12259 var sid = this.meta ? this.meta.id : null;
12260 var recordType = this.recordType, fields = recordType.prototype.fields;
12263 for(var i = 0; i < root.length; i++){
12266 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12267 for(var j = 0, jlen = fields.length; j < jlen; j++){
12268 var f = fields.items[j];
12269 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12270 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12272 values[f.name] = v;
12274 var record = new recordType(values, id);
12276 records[records.length] = record;
12280 totalRecords : records.length
12289 * @class Roo.bootstrap.ComboBox
12290 * @extends Roo.bootstrap.TriggerField
12291 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12292 * @cfg {Boolean} append (true|false) default false
12293 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12294 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12295 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12296 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12297 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12298 * @cfg {Boolean} animate default true
12299 * @cfg {Boolean} emptyResultText only for touch device
12300 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12302 * Create a new ComboBox.
12303 * @param {Object} config Configuration options
12305 Roo.bootstrap.ComboBox = function(config){
12306 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12310 * Fires when the dropdown list is expanded
12311 * @param {Roo.bootstrap.ComboBox} combo This combo box
12316 * Fires when the dropdown list is collapsed
12317 * @param {Roo.bootstrap.ComboBox} combo This combo box
12321 * @event beforeselect
12322 * Fires before a list item is selected. Return false to cancel the selection.
12323 * @param {Roo.bootstrap.ComboBox} combo This combo box
12324 * @param {Roo.data.Record} record The data record returned from the underlying store
12325 * @param {Number} index The index of the selected item in the dropdown list
12327 'beforeselect' : true,
12330 * Fires when a list item is selected
12331 * @param {Roo.bootstrap.ComboBox} combo This combo box
12332 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12333 * @param {Number} index The index of the selected item in the dropdown list
12337 * @event beforequery
12338 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12339 * The event object passed has these properties:
12340 * @param {Roo.bootstrap.ComboBox} combo This combo box
12341 * @param {String} query The query
12342 * @param {Boolean} forceAll true to force "all" query
12343 * @param {Boolean} cancel true to cancel the query
12344 * @param {Object} e The query event object
12346 'beforequery': true,
12349 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12350 * @param {Roo.bootstrap.ComboBox} combo This combo box
12355 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12356 * @param {Roo.bootstrap.ComboBox} combo This combo box
12357 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12362 * Fires when the remove value from the combobox array
12363 * @param {Roo.bootstrap.ComboBox} combo This combo box
12367 * @event afterremove
12368 * Fires when the remove value from the combobox array
12369 * @param {Roo.bootstrap.ComboBox} combo This combo box
12371 'afterremove' : true,
12373 * @event specialfilter
12374 * Fires when specialfilter
12375 * @param {Roo.bootstrap.ComboBox} combo This combo box
12377 'specialfilter' : true,
12380 * Fires when tick the element
12381 * @param {Roo.bootstrap.ComboBox} combo This combo box
12385 * @event touchviewdisplay
12386 * Fires when touch view require special display (default is using displayField)
12387 * @param {Roo.bootstrap.ComboBox} combo This combo box
12388 * @param {Object} cfg set html .
12390 'touchviewdisplay' : true
12395 this.tickItems = [];
12397 this.selectedIndex = -1;
12398 if(this.mode == 'local'){
12399 if(config.queryDelay === undefined){
12400 this.queryDelay = 10;
12402 if(config.minChars === undefined){
12408 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12411 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12412 * rendering into an Roo.Editor, defaults to false)
12415 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12416 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12419 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12422 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12423 * the dropdown list (defaults to undefined, with no header element)
12427 * @cfg {String/Roo.Template} tpl The template to use to render the output
12431 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12433 listWidth: undefined,
12435 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12436 * mode = 'remote' or 'text' if mode = 'local')
12438 displayField: undefined,
12441 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12442 * mode = 'remote' or 'value' if mode = 'local').
12443 * Note: use of a valueField requires the user make a selection
12444 * in order for a value to be mapped.
12446 valueField: undefined,
12448 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12453 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12454 * field's data value (defaults to the underlying DOM element's name)
12456 hiddenName: undefined,
12458 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12462 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12464 selectedClass: 'active',
12467 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12471 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12472 * anchor positions (defaults to 'tl-bl')
12474 listAlign: 'tl-bl?',
12476 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12480 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12481 * query specified by the allQuery config option (defaults to 'query')
12483 triggerAction: 'query',
12485 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12486 * (defaults to 4, does not apply if editable = false)
12490 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12491 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12495 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12496 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12500 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12501 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12505 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12506 * when editable = true (defaults to false)
12508 selectOnFocus:false,
12510 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12512 queryParam: 'query',
12514 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12515 * when mode = 'remote' (defaults to 'Loading...')
12517 loadingText: 'Loading...',
12519 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12523 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12527 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12528 * traditional select (defaults to true)
12532 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12536 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12540 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12541 * listWidth has a higher value)
12545 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12546 * allow the user to set arbitrary text into the field (defaults to false)
12548 forceSelection:false,
12550 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12551 * if typeAhead = true (defaults to 250)
12553 typeAheadDelay : 250,
12555 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12556 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12558 valueNotFoundText : undefined,
12560 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12562 blockFocus : false,
12565 * @cfg {Boolean} disableClear Disable showing of clear button.
12567 disableClear : false,
12569 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12571 alwaysQuery : false,
12574 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12579 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12581 invalidClass : "has-warning",
12584 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12586 validClass : "has-success",
12589 * @cfg {Boolean} specialFilter (true|false) special filter default false
12591 specialFilter : false,
12594 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12596 mobileTouchView : true,
12599 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12601 useNativeIOS : false,
12603 ios_options : false,
12615 btnPosition : 'right',
12616 triggerList : true,
12617 showToggleBtn : true,
12619 emptyResultText: 'Empty',
12620 triggerText : 'Select',
12622 // element that contains real text value.. (when hidden is used..)
12624 getAutoCreate : function()
12629 * Render classic select for iso
12632 if(Roo.isIOS && this.useNativeIOS){
12633 cfg = this.getAutoCreateNativeIOS();
12641 if(Roo.isTouch && this.mobileTouchView){
12642 cfg = this.getAutoCreateTouchView();
12649 if(!this.tickable){
12650 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12651 if(this.name == 'info_year_invest_id_display_name'){
12652 Roo.log('cfg.................................................');
12659 * ComboBox with tickable selections
12662 var align = this.labelAlign || this.parentLabelAlign();
12665 cls : 'form-group roo-combobox-tickable' //input-group
12668 var btn_text_select = '';
12669 var btn_text_done = '';
12670 var btn_text_cancel = '';
12672 if (this.btn_text_show) {
12673 btn_text_select = 'Select';
12674 btn_text_done = 'Done';
12675 btn_text_cancel = 'Cancel';
12680 cls : 'tickable-buttons',
12685 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12686 //html : this.triggerText
12687 html: btn_text_select
12693 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12695 html: btn_text_done
12701 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12703 html: btn_text_cancel
12709 buttons.cn.unshift({
12711 cls: 'roo-select2-search-field-input'
12717 Roo.each(buttons.cn, function(c){
12719 c.cls += ' btn-' + _this.size;
12722 if (_this.disabled) {
12733 cls: 'form-hidden-field'
12737 cls: 'roo-select2-choices',
12741 cls: 'roo-select2-search-field',
12752 cls: 'roo-select2-container input-group roo-select2-container-multi',
12757 // cls: 'typeahead typeahead-long dropdown-menu',
12758 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12763 if(this.hasFeedback && !this.allowBlank){
12767 cls: 'glyphicon form-control-feedback'
12770 combobox.cn.push(feedback);
12774 if (align ==='left' && this.fieldLabel.length) {
12776 cfg.cls += ' roo-form-group-label-left';
12781 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12782 tooltip : 'This field is required'
12787 cls : 'control-label',
12788 html : this.fieldLabel
12800 var labelCfg = cfg.cn[1];
12801 var contentCfg = cfg.cn[2];
12804 if(this.indicatorpos == 'right'){
12810 cls : 'control-label',
12814 html : this.fieldLabel
12818 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12819 tooltip : 'This field is required'
12834 labelCfg = cfg.cn[0];
12835 contentCfg = cfg.cn[1];
12839 if(this.labelWidth > 12){
12840 labelCfg.style = "width: " + this.labelWidth + 'px';
12843 if(this.labelWidth < 13 && this.labelmd == 0){
12844 this.labelmd = this.labelWidth;
12847 if(this.labellg > 0){
12848 labelCfg.cls += ' col-lg-' + this.labellg;
12849 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12852 if(this.labelmd > 0){
12853 labelCfg.cls += ' col-md-' + this.labelmd;
12854 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12857 if(this.labelsm > 0){
12858 labelCfg.cls += ' col-sm-' + this.labelsm;
12859 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12862 if(this.labelxs > 0){
12863 labelCfg.cls += ' col-xs-' + this.labelxs;
12864 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12868 } else if ( this.fieldLabel.length) {
12869 // Roo.log(" label");
12873 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12874 tooltip : 'This field is required'
12878 //cls : 'input-group-addon',
12879 html : this.fieldLabel
12887 if(this.indicatorpos == 'right'){
12892 //cls : 'input-group-addon',
12896 html : this.fieldLabel
12900 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12901 tooltip : 'This field is required'
12916 // Roo.log(" no label && no align");
12923 ['xs','sm','md','lg'].map(function(size){
12924 if (settings[size]) {
12925 cfg.cls += ' col-' + size + '-' + settings[size];
12933 _initEventsCalled : false,
12936 initEvents: function()
12938 if (this._initEventsCalled) { // as we call render... prevent looping...
12941 this._initEventsCalled = true;
12944 throw "can not find store for combo";
12947 this.store = Roo.factory(this.store, Roo.data);
12949 // if we are building from html. then this element is so complex, that we can not really
12950 // use the rendered HTML.
12951 // so we have to trash and replace the previous code.
12952 if (Roo.XComponent.build_from_html) {
12954 // remove this element....
12955 var e = this.el.dom, k=0;
12956 while (e ) { e = e.previousSibling; ++k;}
12961 this.rendered = false;
12963 this.render(this.parent().getChildContainer(true), k);
12969 if(Roo.isIOS && this.useNativeIOS){
12970 this.initIOSView();
12978 if(Roo.isTouch && this.mobileTouchView){
12979 this.initTouchView();
12984 this.initTickableEvents();
12988 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12990 if(this.hiddenName){
12992 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12994 this.hiddenField.dom.value =
12995 this.hiddenValue !== undefined ? this.hiddenValue :
12996 this.value !== undefined ? this.value : '';
12998 // prevent input submission
12999 this.el.dom.removeAttribute('name');
13000 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13005 // this.el.dom.setAttribute('autocomplete', 'off');
13008 var cls = 'x-combo-list';
13010 //this.list = new Roo.Layer({
13011 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13017 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13018 _this.list.setWidth(lw);
13021 this.list.on('mouseover', this.onViewOver, this);
13022 this.list.on('mousemove', this.onViewMove, this);
13024 this.list.on('scroll', this.onViewScroll, this);
13027 this.list.swallowEvent('mousewheel');
13028 this.assetHeight = 0;
13031 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13032 this.assetHeight += this.header.getHeight();
13035 this.innerList = this.list.createChild({cls:cls+'-inner'});
13036 this.innerList.on('mouseover', this.onViewOver, this);
13037 this.innerList.on('mousemove', this.onViewMove, this);
13038 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13040 if(this.allowBlank && !this.pageSize && !this.disableClear){
13041 this.footer = this.list.createChild({cls:cls+'-ft'});
13042 this.pageTb = new Roo.Toolbar(this.footer);
13046 this.footer = this.list.createChild({cls:cls+'-ft'});
13047 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13048 {pageSize: this.pageSize});
13052 if (this.pageTb && this.allowBlank && !this.disableClear) {
13054 this.pageTb.add(new Roo.Toolbar.Fill(), {
13055 cls: 'x-btn-icon x-btn-clear',
13057 handler: function()
13060 _this.clearValue();
13061 _this.onSelect(false, -1);
13066 this.assetHeight += this.footer.getHeight();
13071 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13074 this.view = new Roo.View(this.list, this.tpl, {
13075 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13077 //this.view.wrapEl.setDisplayed(false);
13078 this.view.on('click', this.onViewClick, this);
13082 this.store.on('beforeload', this.onBeforeLoad, this);
13083 this.store.on('load', this.onLoad, this);
13084 this.store.on('loadexception', this.onLoadException, this);
13086 if(this.resizable){
13087 this.resizer = new Roo.Resizable(this.list, {
13088 pinned:true, handles:'se'
13090 this.resizer.on('resize', function(r, w, h){
13091 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13092 this.listWidth = w;
13093 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13094 this.restrictHeight();
13096 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13099 if(!this.editable){
13100 this.editable = true;
13101 this.setEditable(false);
13106 if (typeof(this.events.add.listeners) != 'undefined') {
13108 this.addicon = this.wrap.createChild(
13109 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13111 this.addicon.on('click', function(e) {
13112 this.fireEvent('add', this);
13115 if (typeof(this.events.edit.listeners) != 'undefined') {
13117 this.editicon = this.wrap.createChild(
13118 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13119 if (this.addicon) {
13120 this.editicon.setStyle('margin-left', '40px');
13122 this.editicon.on('click', function(e) {
13124 // we fire even if inothing is selected..
13125 this.fireEvent('edit', this, this.lastData );
13131 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13132 "up" : function(e){
13133 this.inKeyMode = true;
13137 "down" : function(e){
13138 if(!this.isExpanded()){
13139 this.onTriggerClick();
13141 this.inKeyMode = true;
13146 "enter" : function(e){
13147 // this.onViewClick();
13151 if(this.fireEvent("specialkey", this, e)){
13152 this.onViewClick(false);
13158 "esc" : function(e){
13162 "tab" : function(e){
13165 if(this.fireEvent("specialkey", this, e)){
13166 this.onViewClick(false);
13174 doRelay : function(foo, bar, hname){
13175 if(hname == 'down' || this.scope.isExpanded()){
13176 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13185 this.queryDelay = Math.max(this.queryDelay || 10,
13186 this.mode == 'local' ? 10 : 250);
13189 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13191 if(this.typeAhead){
13192 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13194 if(this.editable !== false){
13195 this.inputEl().on("keyup", this.onKeyUp, this);
13197 if(this.forceSelection){
13198 this.inputEl().on('blur', this.doForce, this);
13202 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13203 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13207 initTickableEvents: function()
13211 if(this.hiddenName){
13213 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13215 this.hiddenField.dom.value =
13216 this.hiddenValue !== undefined ? this.hiddenValue :
13217 this.value !== undefined ? this.value : '';
13219 // prevent input submission
13220 this.el.dom.removeAttribute('name');
13221 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13226 // this.list = this.el.select('ul.dropdown-menu',true).first();
13228 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13229 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13230 if(this.triggerList){
13231 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13234 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13235 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13237 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13238 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13240 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13241 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13243 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13244 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13245 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13248 this.cancelBtn.hide();
13253 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13254 _this.list.setWidth(lw);
13257 this.list.on('mouseover', this.onViewOver, this);
13258 this.list.on('mousemove', this.onViewMove, this);
13260 this.list.on('scroll', this.onViewScroll, this);
13263 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>';
13266 this.view = new Roo.View(this.list, this.tpl, {
13267 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13270 //this.view.wrapEl.setDisplayed(false);
13271 this.view.on('click', this.onViewClick, this);
13275 this.store.on('beforeload', this.onBeforeLoad, this);
13276 this.store.on('load', this.onLoad, this);
13277 this.store.on('loadexception', this.onLoadException, this);
13280 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13281 "up" : function(e){
13282 this.inKeyMode = true;
13286 "down" : function(e){
13287 this.inKeyMode = true;
13291 "enter" : function(e){
13292 if(this.fireEvent("specialkey", this, e)){
13293 this.onViewClick(false);
13299 "esc" : function(e){
13300 this.onTickableFooterButtonClick(e, false, false);
13303 "tab" : function(e){
13304 this.fireEvent("specialkey", this, e);
13306 this.onTickableFooterButtonClick(e, false, false);
13313 doRelay : function(e, fn, key){
13314 if(this.scope.isExpanded()){
13315 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13324 this.queryDelay = Math.max(this.queryDelay || 10,
13325 this.mode == 'local' ? 10 : 250);
13328 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13330 if(this.typeAhead){
13331 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13334 if(this.editable !== false){
13335 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13338 this.indicator = this.indicatorEl();
13340 if(this.indicator){
13341 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13342 this.indicator.hide();
13347 onDestroy : function(){
13349 this.view.setStore(null);
13350 this.view.el.removeAllListeners();
13351 this.view.el.remove();
13352 this.view.purgeListeners();
13355 this.list.dom.innerHTML = '';
13359 this.store.un('beforeload', this.onBeforeLoad, this);
13360 this.store.un('load', this.onLoad, this);
13361 this.store.un('loadexception', this.onLoadException, this);
13363 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13367 fireKey : function(e){
13368 if(e.isNavKeyPress() && !this.list.isVisible()){
13369 this.fireEvent("specialkey", this, e);
13374 onResize: function(w, h){
13375 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13377 // if(typeof w != 'number'){
13378 // // we do not handle it!?!?
13381 // var tw = this.trigger.getWidth();
13382 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13383 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13385 // this.inputEl().setWidth( this.adjustWidth('input', x));
13387 // //this.trigger.setStyle('left', x+'px');
13389 // if(this.list && this.listWidth === undefined){
13390 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13391 // this.list.setWidth(lw);
13392 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13400 * Allow or prevent the user from directly editing the field text. If false is passed,
13401 * the user will only be able to select from the items defined in the dropdown list. This method
13402 * is the runtime equivalent of setting the 'editable' config option at config time.
13403 * @param {Boolean} value True to allow the user to directly edit the field text
13405 setEditable : function(value){
13406 if(value == this.editable){
13409 this.editable = value;
13411 this.inputEl().dom.setAttribute('readOnly', true);
13412 this.inputEl().on('mousedown', this.onTriggerClick, this);
13413 this.inputEl().addClass('x-combo-noedit');
13415 this.inputEl().dom.setAttribute('readOnly', false);
13416 this.inputEl().un('mousedown', this.onTriggerClick, this);
13417 this.inputEl().removeClass('x-combo-noedit');
13423 onBeforeLoad : function(combo,opts){
13424 if(!this.hasFocus){
13428 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13430 this.restrictHeight();
13431 this.selectedIndex = -1;
13435 onLoad : function(){
13437 this.hasQuery = false;
13439 if(!this.hasFocus){
13443 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13444 this.loading.hide();
13447 if(this.store.getCount() > 0){
13449 this.restrictHeight();
13450 if(this.lastQuery == this.allQuery){
13451 if(this.editable && !this.tickable){
13452 this.inputEl().dom.select();
13456 !this.selectByValue(this.value, true) &&
13459 !this.store.lastOptions ||
13460 typeof(this.store.lastOptions.add) == 'undefined' ||
13461 this.store.lastOptions.add != true
13464 this.select(0, true);
13467 if(this.autoFocus){
13470 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13471 this.taTask.delay(this.typeAheadDelay);
13475 this.onEmptyResults();
13481 onLoadException : function()
13483 this.hasQuery = false;
13485 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13486 this.loading.hide();
13489 if(this.tickable && this.editable){
13494 // only causes errors at present
13495 //Roo.log(this.store.reader.jsonData);
13496 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13498 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13504 onTypeAhead : function(){
13505 if(this.store.getCount() > 0){
13506 var r = this.store.getAt(0);
13507 var newValue = r.data[this.displayField];
13508 var len = newValue.length;
13509 var selStart = this.getRawValue().length;
13511 if(selStart != len){
13512 this.setRawValue(newValue);
13513 this.selectText(selStart, newValue.length);
13519 onSelect : function(record, index){
13521 if(this.fireEvent('beforeselect', this, record, index) !== false){
13523 this.setFromData(index > -1 ? record.data : false);
13526 this.fireEvent('select', this, record, index);
13531 * Returns the currently selected field value or empty string if no value is set.
13532 * @return {String} value The selected value
13534 getValue : function()
13536 if(Roo.isIOS && this.useNativeIOS){
13537 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13541 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13544 if(this.valueField){
13545 return typeof this.value != 'undefined' ? this.value : '';
13547 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13551 getRawValue : function()
13553 if(Roo.isIOS && this.useNativeIOS){
13554 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13557 var v = this.inputEl().getValue();
13563 * Clears any text/value currently set in the field
13565 clearValue : function(){
13567 if(this.hiddenField){
13568 this.hiddenField.dom.value = '';
13571 this.setRawValue('');
13572 this.lastSelectionText = '';
13573 this.lastData = false;
13575 var close = this.closeTriggerEl();
13586 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13587 * will be displayed in the field. If the value does not match the data value of an existing item,
13588 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13589 * Otherwise the field will be blank (although the value will still be set).
13590 * @param {String} value The value to match
13592 setValue : function(v)
13594 if(Roo.isIOS && this.useNativeIOS){
13595 this.setIOSValue(v);
13605 if(this.valueField){
13606 var r = this.findRecord(this.valueField, v);
13608 text = r.data[this.displayField];
13609 }else if(this.valueNotFoundText !== undefined){
13610 text = this.valueNotFoundText;
13613 this.lastSelectionText = text;
13614 if(this.hiddenField){
13615 this.hiddenField.dom.value = v;
13617 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13620 var close = this.closeTriggerEl();
13623 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13629 * @property {Object} the last set data for the element
13634 * Sets the value of the field based on a object which is related to the record format for the store.
13635 * @param {Object} value the value to set as. or false on reset?
13637 setFromData : function(o){
13644 var dv = ''; // display value
13645 var vv = ''; // value value..
13647 if (this.displayField) {
13648 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13650 // this is an error condition!!!
13651 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13654 if(this.valueField){
13655 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13658 var close = this.closeTriggerEl();
13661 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13664 if(this.hiddenField){
13665 this.hiddenField.dom.value = vv;
13667 this.lastSelectionText = dv;
13668 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13672 // no hidden field.. - we store the value in 'value', but still display
13673 // display field!!!!
13674 this.lastSelectionText = dv;
13675 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13682 reset : function(){
13683 // overridden so that last data is reset..
13690 this.setValue(this.originalValue);
13691 //this.clearInvalid();
13692 this.lastData = false;
13694 this.view.clearSelections();
13700 findRecord : function(prop, value){
13702 if(this.store.getCount() > 0){
13703 this.store.each(function(r){
13704 if(r.data[prop] == value){
13714 getName: function()
13716 // returns hidden if it's set..
13717 if (!this.rendered) {return ''};
13718 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13722 onViewMove : function(e, t){
13723 this.inKeyMode = false;
13727 onViewOver : function(e, t){
13728 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13731 var item = this.view.findItemFromChild(t);
13734 var index = this.view.indexOf(item);
13735 this.select(index, false);
13740 onViewClick : function(view, doFocus, el, e)
13742 var index = this.view.getSelectedIndexes()[0];
13744 var r = this.store.getAt(index);
13748 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13755 Roo.each(this.tickItems, function(v,k){
13757 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13759 _this.tickItems.splice(k, 1);
13761 if(typeof(e) == 'undefined' && view == false){
13762 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13774 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13775 this.tickItems.push(r.data);
13778 if(typeof(e) == 'undefined' && view == false){
13779 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13786 this.onSelect(r, index);
13788 if(doFocus !== false && !this.blockFocus){
13789 this.inputEl().focus();
13794 restrictHeight : function(){
13795 //this.innerList.dom.style.height = '';
13796 //var inner = this.innerList.dom;
13797 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13798 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13799 //this.list.beginUpdate();
13800 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13801 this.list.alignTo(this.inputEl(), this.listAlign);
13802 this.list.alignTo(this.inputEl(), this.listAlign);
13803 //this.list.endUpdate();
13807 onEmptyResults : function(){
13809 if(this.tickable && this.editable){
13810 this.restrictHeight();
13818 * Returns true if the dropdown list is expanded, else false.
13820 isExpanded : function(){
13821 return this.list.isVisible();
13825 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13826 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13827 * @param {String} value The data value of the item to select
13828 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13829 * selected item if it is not currently in view (defaults to true)
13830 * @return {Boolean} True if the value matched an item in the list, else false
13832 selectByValue : function(v, scrollIntoView){
13833 if(v !== undefined && v !== null){
13834 var r = this.findRecord(this.valueField || this.displayField, v);
13836 this.select(this.store.indexOf(r), scrollIntoView);
13844 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13845 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13846 * @param {Number} index The zero-based index of the list item to select
13847 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13848 * selected item if it is not currently in view (defaults to true)
13850 select : function(index, scrollIntoView){
13851 this.selectedIndex = index;
13852 this.view.select(index);
13853 if(scrollIntoView !== false){
13854 var el = this.view.getNode(index);
13856 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13859 this.list.scrollChildIntoView(el, false);
13865 selectNext : function(){
13866 var ct = this.store.getCount();
13868 if(this.selectedIndex == -1){
13870 }else if(this.selectedIndex < ct-1){
13871 this.select(this.selectedIndex+1);
13877 selectPrev : function(){
13878 var ct = this.store.getCount();
13880 if(this.selectedIndex == -1){
13882 }else if(this.selectedIndex != 0){
13883 this.select(this.selectedIndex-1);
13889 onKeyUp : function(e){
13890 if(this.editable !== false && !e.isSpecialKey()){
13891 this.lastKey = e.getKey();
13892 this.dqTask.delay(this.queryDelay);
13897 validateBlur : function(){
13898 return !this.list || !this.list.isVisible();
13902 initQuery : function(){
13904 var v = this.getRawValue();
13906 if(this.tickable && this.editable){
13907 v = this.tickableInputEl().getValue();
13914 doForce : function(){
13915 if(this.inputEl().dom.value.length > 0){
13916 this.inputEl().dom.value =
13917 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13923 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13924 * query allowing the query action to be canceled if needed.
13925 * @param {String} query The SQL query to execute
13926 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13927 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13928 * saved in the current store (defaults to false)
13930 doQuery : function(q, forceAll){
13932 if(q === undefined || q === null){
13937 forceAll: forceAll,
13941 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13946 forceAll = qe.forceAll;
13947 if(forceAll === true || (q.length >= this.minChars)){
13949 this.hasQuery = true;
13951 if(this.lastQuery != q || this.alwaysQuery){
13952 this.lastQuery = q;
13953 if(this.mode == 'local'){
13954 this.selectedIndex = -1;
13956 this.store.clearFilter();
13959 if(this.specialFilter){
13960 this.fireEvent('specialfilter', this);
13965 this.store.filter(this.displayField, q);
13968 this.store.fireEvent("datachanged", this.store);
13975 this.store.baseParams[this.queryParam] = q;
13977 var options = {params : this.getParams(q)};
13980 options.add = true;
13981 options.params.start = this.page * this.pageSize;
13984 this.store.load(options);
13987 * this code will make the page width larger, at the beginning, the list not align correctly,
13988 * we should expand the list on onLoad
13989 * so command out it
13994 this.selectedIndex = -1;
13999 this.loadNext = false;
14003 getParams : function(q){
14005 //p[this.queryParam] = q;
14009 p.limit = this.pageSize;
14015 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14017 collapse : function(){
14018 if(!this.isExpanded()){
14024 this.hasFocus = false;
14028 this.cancelBtn.hide();
14029 this.trigger.show();
14032 this.tickableInputEl().dom.value = '';
14033 this.tickableInputEl().blur();
14038 Roo.get(document).un('mousedown', this.collapseIf, this);
14039 Roo.get(document).un('mousewheel', this.collapseIf, this);
14040 if (!this.editable) {
14041 Roo.get(document).un('keydown', this.listKeyPress, this);
14043 this.fireEvent('collapse', this);
14049 collapseIf : function(e){
14050 var in_combo = e.within(this.el);
14051 var in_list = e.within(this.list);
14052 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14054 if (in_combo || in_list || is_list) {
14055 //e.stopPropagation();
14060 this.onTickableFooterButtonClick(e, false, false);
14068 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14070 expand : function(){
14072 if(this.isExpanded() || !this.hasFocus){
14076 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14077 this.list.setWidth(lw);
14083 this.restrictHeight();
14087 this.tickItems = Roo.apply([], this.item);
14090 this.cancelBtn.show();
14091 this.trigger.hide();
14094 this.tickableInputEl().focus();
14099 Roo.get(document).on('mousedown', this.collapseIf, this);
14100 Roo.get(document).on('mousewheel', this.collapseIf, this);
14101 if (!this.editable) {
14102 Roo.get(document).on('keydown', this.listKeyPress, this);
14105 this.fireEvent('expand', this);
14109 // Implements the default empty TriggerField.onTriggerClick function
14110 onTriggerClick : function(e)
14112 Roo.log('trigger click');
14114 if(this.disabled || !this.triggerList){
14119 this.loadNext = false;
14121 if(this.isExpanded()){
14123 if (!this.blockFocus) {
14124 this.inputEl().focus();
14128 this.hasFocus = true;
14129 if(this.triggerAction == 'all') {
14130 this.doQuery(this.allQuery, true);
14132 this.doQuery(this.getRawValue());
14134 if (!this.blockFocus) {
14135 this.inputEl().focus();
14140 onTickableTriggerClick : function(e)
14147 this.loadNext = false;
14148 this.hasFocus = true;
14150 if(this.triggerAction == 'all') {
14151 this.doQuery(this.allQuery, true);
14153 this.doQuery(this.getRawValue());
14157 onSearchFieldClick : function(e)
14159 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14160 this.onTickableFooterButtonClick(e, false, false);
14164 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14169 this.loadNext = false;
14170 this.hasFocus = true;
14172 if(this.triggerAction == 'all') {
14173 this.doQuery(this.allQuery, true);
14175 this.doQuery(this.getRawValue());
14179 listKeyPress : function(e)
14181 //Roo.log('listkeypress');
14182 // scroll to first matching element based on key pres..
14183 if (e.isSpecialKey()) {
14186 var k = String.fromCharCode(e.getKey()).toUpperCase();
14189 var csel = this.view.getSelectedNodes();
14190 var cselitem = false;
14192 var ix = this.view.indexOf(csel[0]);
14193 cselitem = this.store.getAt(ix);
14194 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14200 this.store.each(function(v) {
14202 // start at existing selection.
14203 if (cselitem.id == v.id) {
14209 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14210 match = this.store.indexOf(v);
14216 if (match === false) {
14217 return true; // no more action?
14220 this.view.select(match);
14221 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14222 sn.scrollIntoView(sn.dom.parentNode, false);
14225 onViewScroll : function(e, t){
14227 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){
14231 this.hasQuery = true;
14233 this.loading = this.list.select('.loading', true).first();
14235 if(this.loading === null){
14236 this.list.createChild({
14238 cls: 'loading roo-select2-more-results roo-select2-active',
14239 html: 'Loading more results...'
14242 this.loading = this.list.select('.loading', true).first();
14244 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14246 this.loading.hide();
14249 this.loading.show();
14254 this.loadNext = true;
14256 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14261 addItem : function(o)
14263 var dv = ''; // display value
14265 if (this.displayField) {
14266 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14268 // this is an error condition!!!
14269 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14276 var choice = this.choices.createChild({
14278 cls: 'roo-select2-search-choice',
14287 cls: 'roo-select2-search-choice-close',
14292 }, this.searchField);
14294 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14296 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14304 this.inputEl().dom.value = '';
14309 onRemoveItem : function(e, _self, o)
14311 e.preventDefault();
14313 this.lastItem = Roo.apply([], this.item);
14315 var index = this.item.indexOf(o.data) * 1;
14318 Roo.log('not this item?!');
14322 this.item.splice(index, 1);
14327 this.fireEvent('remove', this, e);
14333 syncValue : function()
14335 if(!this.item.length){
14342 Roo.each(this.item, function(i){
14343 if(_this.valueField){
14344 value.push(i[_this.valueField]);
14351 this.value = value.join(',');
14353 if(this.hiddenField){
14354 this.hiddenField.dom.value = this.value;
14357 this.store.fireEvent("datachanged", this.store);
14362 clearItem : function()
14364 if(!this.multiple){
14370 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14378 if(this.tickable && !Roo.isTouch){
14379 this.view.refresh();
14383 inputEl: function ()
14385 if(Roo.isIOS && this.useNativeIOS){
14386 return this.el.select('select.roo-ios-select', true).first();
14389 if(Roo.isTouch && this.mobileTouchView){
14390 return this.el.select('input.form-control',true).first();
14394 return this.searchField;
14397 return this.el.select('input.form-control',true).first();
14400 onTickableFooterButtonClick : function(e, btn, el)
14402 e.preventDefault();
14404 this.lastItem = Roo.apply([], this.item);
14406 if(btn && btn.name == 'cancel'){
14407 this.tickItems = Roo.apply([], this.item);
14416 Roo.each(this.tickItems, function(o){
14424 validate : function()
14426 var v = this.getRawValue();
14429 v = this.getValue();
14432 if(this.disabled || this.allowBlank || v.length){
14437 this.markInvalid();
14441 tickableInputEl : function()
14443 if(!this.tickable || !this.editable){
14444 return this.inputEl();
14447 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14451 getAutoCreateTouchView : function()
14456 cls: 'form-group' //input-group
14462 type : this.inputType,
14463 cls : 'form-control x-combo-noedit',
14464 autocomplete: 'new-password',
14465 placeholder : this.placeholder || '',
14470 input.name = this.name;
14474 input.cls += ' input-' + this.size;
14477 if (this.disabled) {
14478 input.disabled = true;
14489 inputblock.cls += ' input-group';
14491 inputblock.cn.unshift({
14493 cls : 'input-group-addon',
14498 if(this.removable && !this.multiple){
14499 inputblock.cls += ' roo-removable';
14501 inputblock.cn.push({
14504 cls : 'roo-combo-removable-btn close'
14508 if(this.hasFeedback && !this.allowBlank){
14510 inputblock.cls += ' has-feedback';
14512 inputblock.cn.push({
14514 cls: 'glyphicon form-control-feedback'
14521 inputblock.cls += (this.before) ? '' : ' input-group';
14523 inputblock.cn.push({
14525 cls : 'input-group-addon',
14536 cls: 'form-hidden-field'
14550 cls: 'form-hidden-field'
14554 cls: 'roo-select2-choices',
14558 cls: 'roo-select2-search-field',
14571 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14577 if(!this.multiple && this.showToggleBtn){
14584 if (this.caret != false) {
14587 cls: 'fa fa-' + this.caret
14594 cls : 'input-group-addon btn dropdown-toggle',
14599 cls: 'combobox-clear',
14613 combobox.cls += ' roo-select2-container-multi';
14616 var align = this.labelAlign || this.parentLabelAlign();
14618 if (align ==='left' && this.fieldLabel.length) {
14623 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14624 tooltip : 'This field is required'
14628 cls : 'control-label',
14629 html : this.fieldLabel
14640 var labelCfg = cfg.cn[1];
14641 var contentCfg = cfg.cn[2];
14644 if(this.indicatorpos == 'right'){
14648 cls : 'control-label',
14649 html : this.fieldLabel,
14653 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14654 tooltip : 'This field is required'
14667 labelCfg = cfg.cn[0];
14668 contentCfg = cfg.cn[2];
14670 if(this.labelWidth > 12){
14671 labelCfg.style = "width: " + this.labelWidth + 'px';
14674 if(this.labelWidth < 13 && this.labelmd == 0){
14675 this.labelmd = this.labelWidth;
14678 if(this.labellg > 0){
14679 labelCfg.cls += ' col-lg-' + this.labellg;
14680 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14683 if(this.labelmd > 0){
14684 labelCfg.cls += ' col-md-' + this.labelmd;
14685 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14688 if(this.labelsm > 0){
14689 labelCfg.cls += ' col-sm-' + this.labelsm;
14690 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14693 if(this.labelxs > 0){
14694 labelCfg.cls += ' col-xs-' + this.labelxs;
14695 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14699 } else if ( this.fieldLabel.length) {
14703 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14704 tooltip : 'This field is required'
14708 cls : 'control-label',
14709 html : this.fieldLabel
14720 if(this.indicatorpos == 'right'){
14724 cls : 'control-label',
14725 html : this.fieldLabel,
14729 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14730 tooltip : 'This field is required'
14747 var settings = this;
14749 ['xs','sm','md','lg'].map(function(size){
14750 if (settings[size]) {
14751 cfg.cls += ' col-' + size + '-' + settings[size];
14758 initTouchView : function()
14760 this.renderTouchView();
14762 this.touchViewEl.on('scroll', function(){
14763 this.el.dom.scrollTop = 0;
14766 this.originalValue = this.getValue();
14768 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14770 this.inputEl().on("click", this.showTouchView, this);
14771 if (this.triggerEl) {
14772 this.triggerEl.on("click", this.showTouchView, this);
14776 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14777 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14779 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14781 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14782 this.store.on('load', this.onTouchViewLoad, this);
14783 this.store.on('loadexception', this.onTouchViewLoadException, this);
14785 if(this.hiddenName){
14787 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14789 this.hiddenField.dom.value =
14790 this.hiddenValue !== undefined ? this.hiddenValue :
14791 this.value !== undefined ? this.value : '';
14793 this.el.dom.removeAttribute('name');
14794 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14798 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14799 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14802 if(this.removable && !this.multiple){
14803 var close = this.closeTriggerEl();
14805 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14806 close.on('click', this.removeBtnClick, this, close);
14810 * fix the bug in Safari iOS8
14812 this.inputEl().on("focus", function(e){
14813 document.activeElement.blur();
14821 renderTouchView : function()
14823 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14824 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14826 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14827 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14829 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14830 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14831 this.touchViewBodyEl.setStyle('overflow', 'auto');
14833 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14834 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14836 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14837 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14841 showTouchView : function()
14847 this.touchViewHeaderEl.hide();
14849 if(this.modalTitle.length){
14850 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14851 this.touchViewHeaderEl.show();
14854 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14855 this.touchViewEl.show();
14857 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14858 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14859 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14861 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14863 if(this.modalTitle.length){
14864 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14867 this.touchViewBodyEl.setHeight(bodyHeight);
14871 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14873 this.touchViewEl.addClass('in');
14876 this.doTouchViewQuery();
14880 hideTouchView : function()
14882 this.touchViewEl.removeClass('in');
14886 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14888 this.touchViewEl.setStyle('display', 'none');
14893 setTouchViewValue : function()
14900 Roo.each(this.tickItems, function(o){
14905 this.hideTouchView();
14908 doTouchViewQuery : function()
14917 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14921 if(!this.alwaysQuery || this.mode == 'local'){
14922 this.onTouchViewLoad();
14929 onTouchViewBeforeLoad : function(combo,opts)
14935 onTouchViewLoad : function()
14937 if(this.store.getCount() < 1){
14938 this.onTouchViewEmptyResults();
14942 this.clearTouchView();
14944 var rawValue = this.getRawValue();
14946 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14948 this.tickItems = [];
14950 this.store.data.each(function(d, rowIndex){
14951 var row = this.touchViewListGroup.createChild(template);
14953 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14954 row.addClass(d.data.cls);
14957 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14960 html : d.data[this.displayField]
14963 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14964 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14967 row.removeClass('selected');
14968 if(!this.multiple && this.valueField &&
14969 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14972 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14973 row.addClass('selected');
14976 if(this.multiple && this.valueField &&
14977 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14981 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14982 this.tickItems.push(d.data);
14985 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14989 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14991 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14993 if(this.modalTitle.length){
14994 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14997 var listHeight = this.touchViewListGroup.getHeight();
15001 if(firstChecked && listHeight > bodyHeight){
15002 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15007 onTouchViewLoadException : function()
15009 this.hideTouchView();
15012 onTouchViewEmptyResults : function()
15014 this.clearTouchView();
15016 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15018 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15022 clearTouchView : function()
15024 this.touchViewListGroup.dom.innerHTML = '';
15027 onTouchViewClick : function(e, el, o)
15029 e.preventDefault();
15032 var rowIndex = o.rowIndex;
15034 var r = this.store.getAt(rowIndex);
15036 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15038 if(!this.multiple){
15039 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15040 c.dom.removeAttribute('checked');
15043 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15045 this.setFromData(r.data);
15047 var close = this.closeTriggerEl();
15053 this.hideTouchView();
15055 this.fireEvent('select', this, r, rowIndex);
15060 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15061 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15062 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15066 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15067 this.addItem(r.data);
15068 this.tickItems.push(r.data);
15072 getAutoCreateNativeIOS : function()
15075 cls: 'form-group' //input-group,
15080 cls : 'roo-ios-select'
15084 combobox.name = this.name;
15087 if (this.disabled) {
15088 combobox.disabled = true;
15091 var settings = this;
15093 ['xs','sm','md','lg'].map(function(size){
15094 if (settings[size]) {
15095 cfg.cls += ' col-' + size + '-' + settings[size];
15105 initIOSView : function()
15107 this.store.on('load', this.onIOSViewLoad, this);
15112 onIOSViewLoad : function()
15114 if(this.store.getCount() < 1){
15118 this.clearIOSView();
15120 if(this.allowBlank) {
15122 var default_text = '-- SELECT --';
15124 var opt = this.inputEl().createChild({
15127 html : default_text
15131 o[this.valueField] = 0;
15132 o[this.displayField] = default_text;
15134 this.ios_options.push({
15141 this.store.data.each(function(d, rowIndex){
15145 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15146 html = d.data[this.displayField];
15151 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15152 value = d.data[this.valueField];
15161 if(this.value == d.data[this.valueField]){
15162 option['selected'] = true;
15165 var opt = this.inputEl().createChild(option);
15167 this.ios_options.push({
15174 this.inputEl().on('change', function(){
15175 this.fireEvent('select', this);
15180 clearIOSView: function()
15182 this.inputEl().dom.innerHTML = '';
15184 this.ios_options = [];
15187 setIOSValue: function(v)
15191 if(!this.ios_options){
15195 Roo.each(this.ios_options, function(opts){
15197 opts.el.dom.removeAttribute('selected');
15199 if(opts.data[this.valueField] != v){
15203 opts.el.dom.setAttribute('selected', true);
15209 * @cfg {Boolean} grow
15213 * @cfg {Number} growMin
15217 * @cfg {Number} growMax
15226 Roo.apply(Roo.bootstrap.ComboBox, {
15230 cls: 'modal-header',
15252 cls: 'list-group-item',
15256 cls: 'roo-combobox-list-group-item-value'
15260 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15274 listItemCheckbox : {
15276 cls: 'list-group-item',
15280 cls: 'roo-combobox-list-group-item-value'
15284 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15300 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15305 cls: 'modal-footer',
15313 cls: 'col-xs-6 text-left',
15316 cls: 'btn btn-danger roo-touch-view-cancel',
15322 cls: 'col-xs-6 text-right',
15325 cls: 'btn btn-success roo-touch-view-ok',
15336 Roo.apply(Roo.bootstrap.ComboBox, {
15338 touchViewTemplate : {
15340 cls: 'modal fade roo-combobox-touch-view',
15344 cls: 'modal-dialog',
15345 style : 'position:fixed', // we have to fix position....
15349 cls: 'modal-content',
15351 Roo.bootstrap.ComboBox.header,
15352 Roo.bootstrap.ComboBox.body,
15353 Roo.bootstrap.ComboBox.footer
15362 * Ext JS Library 1.1.1
15363 * Copyright(c) 2006-2007, Ext JS, LLC.
15365 * Originally Released Under LGPL - original licence link has changed is not relivant.
15368 * <script type="text/javascript">
15373 * @extends Roo.util.Observable
15374 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15375 * This class also supports single and multi selection modes. <br>
15376 * Create a data model bound view:
15378 var store = new Roo.data.Store(...);
15380 var view = new Roo.View({
15382 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15384 singleSelect: true,
15385 selectedClass: "ydataview-selected",
15389 // listen for node click?
15390 view.on("click", function(vw, index, node, e){
15391 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15395 dataModel.load("foobar.xml");
15397 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15399 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15400 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15402 * Note: old style constructor is still suported (container, template, config)
15405 * Create a new View
15406 * @param {Object} config The config object
15409 Roo.View = function(config, depreciated_tpl, depreciated_config){
15411 this.parent = false;
15413 if (typeof(depreciated_tpl) == 'undefined') {
15414 // new way.. - universal constructor.
15415 Roo.apply(this, config);
15416 this.el = Roo.get(this.el);
15419 this.el = Roo.get(config);
15420 this.tpl = depreciated_tpl;
15421 Roo.apply(this, depreciated_config);
15423 this.wrapEl = this.el.wrap().wrap();
15424 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15427 if(typeof(this.tpl) == "string"){
15428 this.tpl = new Roo.Template(this.tpl);
15430 // support xtype ctors..
15431 this.tpl = new Roo.factory(this.tpl, Roo);
15435 this.tpl.compile();
15440 * @event beforeclick
15441 * Fires before a click is processed. Returns false to cancel the default action.
15442 * @param {Roo.View} this
15443 * @param {Number} index The index of the target node
15444 * @param {HTMLElement} node The target node
15445 * @param {Roo.EventObject} e The raw event object
15447 "beforeclick" : true,
15450 * Fires when a template node is clicked.
15451 * @param {Roo.View} this
15452 * @param {Number} index The index of the target node
15453 * @param {HTMLElement} node The target node
15454 * @param {Roo.EventObject} e The raw event object
15459 * Fires when a template node is double clicked.
15460 * @param {Roo.View} this
15461 * @param {Number} index The index of the target node
15462 * @param {HTMLElement} node The target node
15463 * @param {Roo.EventObject} e The raw event object
15467 * @event contextmenu
15468 * Fires when a template node is right clicked.
15469 * @param {Roo.View} this
15470 * @param {Number} index The index of the target node
15471 * @param {HTMLElement} node The target node
15472 * @param {Roo.EventObject} e The raw event object
15474 "contextmenu" : true,
15476 * @event selectionchange
15477 * Fires when the selected nodes change.
15478 * @param {Roo.View} this
15479 * @param {Array} selections Array of the selected nodes
15481 "selectionchange" : true,
15484 * @event beforeselect
15485 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15486 * @param {Roo.View} this
15487 * @param {HTMLElement} node The node to be selected
15488 * @param {Array} selections Array of currently selected nodes
15490 "beforeselect" : true,
15492 * @event preparedata
15493 * Fires on every row to render, to allow you to change the data.
15494 * @param {Roo.View} this
15495 * @param {Object} data to be rendered (change this)
15497 "preparedata" : true
15505 "click": this.onClick,
15506 "dblclick": this.onDblClick,
15507 "contextmenu": this.onContextMenu,
15511 this.selections = [];
15513 this.cmp = new Roo.CompositeElementLite([]);
15515 this.store = Roo.factory(this.store, Roo.data);
15516 this.setStore(this.store, true);
15519 if ( this.footer && this.footer.xtype) {
15521 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15523 this.footer.dataSource = this.store;
15524 this.footer.container = fctr;
15525 this.footer = Roo.factory(this.footer, Roo);
15526 fctr.insertFirst(this.el);
15528 // this is a bit insane - as the paging toolbar seems to detach the el..
15529 // dom.parentNode.parentNode.parentNode
15530 // they get detached?
15534 Roo.View.superclass.constructor.call(this);
15539 Roo.extend(Roo.View, Roo.util.Observable, {
15542 * @cfg {Roo.data.Store} store Data store to load data from.
15547 * @cfg {String|Roo.Element} el The container element.
15552 * @cfg {String|Roo.Template} tpl The template used by this View
15556 * @cfg {String} dataName the named area of the template to use as the data area
15557 * Works with domtemplates roo-name="name"
15561 * @cfg {String} selectedClass The css class to add to selected nodes
15563 selectedClass : "x-view-selected",
15565 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15570 * @cfg {String} text to display on mask (default Loading)
15574 * @cfg {Boolean} multiSelect Allow multiple selection
15576 multiSelect : false,
15578 * @cfg {Boolean} singleSelect Allow single selection
15580 singleSelect: false,
15583 * @cfg {Boolean} toggleSelect - selecting
15585 toggleSelect : false,
15588 * @cfg {Boolean} tickable - selecting
15593 * Returns the element this view is bound to.
15594 * @return {Roo.Element}
15596 getEl : function(){
15597 return this.wrapEl;
15603 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15605 refresh : function(){
15606 //Roo.log('refresh');
15609 // if we are using something like 'domtemplate', then
15610 // the what gets used is:
15611 // t.applySubtemplate(NAME, data, wrapping data..)
15612 // the outer template then get' applied with
15613 // the store 'extra data'
15614 // and the body get's added to the
15615 // roo-name="data" node?
15616 // <span class='roo-tpl-{name}'></span> ?????
15620 this.clearSelections();
15621 this.el.update("");
15623 var records = this.store.getRange();
15624 if(records.length < 1) {
15626 // is this valid?? = should it render a template??
15628 this.el.update(this.emptyText);
15632 if (this.dataName) {
15633 this.el.update(t.apply(this.store.meta)); //????
15634 el = this.el.child('.roo-tpl-' + this.dataName);
15637 for(var i = 0, len = records.length; i < len; i++){
15638 var data = this.prepareData(records[i].data, i, records[i]);
15639 this.fireEvent("preparedata", this, data, i, records[i]);
15641 var d = Roo.apply({}, data);
15644 Roo.apply(d, {'roo-id' : Roo.id()});
15648 Roo.each(this.parent.item, function(item){
15649 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15652 Roo.apply(d, {'roo-data-checked' : 'checked'});
15656 html[html.length] = Roo.util.Format.trim(
15658 t.applySubtemplate(this.dataName, d, this.store.meta) :
15665 el.update(html.join(""));
15666 this.nodes = el.dom.childNodes;
15667 this.updateIndexes(0);
15672 * Function to override to reformat the data that is sent to
15673 * the template for each node.
15674 * DEPRICATED - use the preparedata event handler.
15675 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15676 * a JSON object for an UpdateManager bound view).
15678 prepareData : function(data, index, record)
15680 this.fireEvent("preparedata", this, data, index, record);
15684 onUpdate : function(ds, record){
15685 // Roo.log('on update');
15686 this.clearSelections();
15687 var index = this.store.indexOf(record);
15688 var n = this.nodes[index];
15689 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15690 n.parentNode.removeChild(n);
15691 this.updateIndexes(index, index);
15697 onAdd : function(ds, records, index)
15699 //Roo.log(['on Add', ds, records, index] );
15700 this.clearSelections();
15701 if(this.nodes.length == 0){
15705 var n = this.nodes[index];
15706 for(var i = 0, len = records.length; i < len; i++){
15707 var d = this.prepareData(records[i].data, i, records[i]);
15709 this.tpl.insertBefore(n, d);
15712 this.tpl.append(this.el, d);
15715 this.updateIndexes(index);
15718 onRemove : function(ds, record, index){
15719 // Roo.log('onRemove');
15720 this.clearSelections();
15721 var el = this.dataName ?
15722 this.el.child('.roo-tpl-' + this.dataName) :
15725 el.dom.removeChild(this.nodes[index]);
15726 this.updateIndexes(index);
15730 * Refresh an individual node.
15731 * @param {Number} index
15733 refreshNode : function(index){
15734 this.onUpdate(this.store, this.store.getAt(index));
15737 updateIndexes : function(startIndex, endIndex){
15738 var ns = this.nodes;
15739 startIndex = startIndex || 0;
15740 endIndex = endIndex || ns.length - 1;
15741 for(var i = startIndex; i <= endIndex; i++){
15742 ns[i].nodeIndex = i;
15747 * Changes the data store this view uses and refresh the view.
15748 * @param {Store} store
15750 setStore : function(store, initial){
15751 if(!initial && this.store){
15752 this.store.un("datachanged", this.refresh);
15753 this.store.un("add", this.onAdd);
15754 this.store.un("remove", this.onRemove);
15755 this.store.un("update", this.onUpdate);
15756 this.store.un("clear", this.refresh);
15757 this.store.un("beforeload", this.onBeforeLoad);
15758 this.store.un("load", this.onLoad);
15759 this.store.un("loadexception", this.onLoad);
15763 store.on("datachanged", this.refresh, this);
15764 store.on("add", this.onAdd, this);
15765 store.on("remove", this.onRemove, this);
15766 store.on("update", this.onUpdate, this);
15767 store.on("clear", this.refresh, this);
15768 store.on("beforeload", this.onBeforeLoad, this);
15769 store.on("load", this.onLoad, this);
15770 store.on("loadexception", this.onLoad, this);
15778 * onbeforeLoad - masks the loading area.
15781 onBeforeLoad : function(store,opts)
15783 //Roo.log('onBeforeLoad');
15785 this.el.update("");
15787 this.el.mask(this.mask ? this.mask : "Loading" );
15789 onLoad : function ()
15796 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15797 * @param {HTMLElement} node
15798 * @return {HTMLElement} The template node
15800 findItemFromChild : function(node){
15801 var el = this.dataName ?
15802 this.el.child('.roo-tpl-' + this.dataName,true) :
15805 if(!node || node.parentNode == el){
15808 var p = node.parentNode;
15809 while(p && p != el){
15810 if(p.parentNode == el){
15819 onClick : function(e){
15820 var item = this.findItemFromChild(e.getTarget());
15822 var index = this.indexOf(item);
15823 if(this.onItemClick(item, index, e) !== false){
15824 this.fireEvent("click", this, index, item, e);
15827 this.clearSelections();
15832 onContextMenu : function(e){
15833 var item = this.findItemFromChild(e.getTarget());
15835 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15840 onDblClick : function(e){
15841 var item = this.findItemFromChild(e.getTarget());
15843 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15847 onItemClick : function(item, index, e)
15849 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15852 if (this.toggleSelect) {
15853 var m = this.isSelected(item) ? 'unselect' : 'select';
15856 _t[m](item, true, false);
15859 if(this.multiSelect || this.singleSelect){
15860 if(this.multiSelect && e.shiftKey && this.lastSelection){
15861 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15863 this.select(item, this.multiSelect && e.ctrlKey);
15864 this.lastSelection = item;
15867 if(!this.tickable){
15868 e.preventDefault();
15876 * Get the number of selected nodes.
15879 getSelectionCount : function(){
15880 return this.selections.length;
15884 * Get the currently selected nodes.
15885 * @return {Array} An array of HTMLElements
15887 getSelectedNodes : function(){
15888 return this.selections;
15892 * Get the indexes of the selected nodes.
15895 getSelectedIndexes : function(){
15896 var indexes = [], s = this.selections;
15897 for(var i = 0, len = s.length; i < len; i++){
15898 indexes.push(s[i].nodeIndex);
15904 * Clear all selections
15905 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15907 clearSelections : function(suppressEvent){
15908 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15909 this.cmp.elements = this.selections;
15910 this.cmp.removeClass(this.selectedClass);
15911 this.selections = [];
15912 if(!suppressEvent){
15913 this.fireEvent("selectionchange", this, this.selections);
15919 * Returns true if the passed node is selected
15920 * @param {HTMLElement/Number} node The node or node index
15921 * @return {Boolean}
15923 isSelected : function(node){
15924 var s = this.selections;
15928 node = this.getNode(node);
15929 return s.indexOf(node) !== -1;
15934 * @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
15935 * @param {Boolean} keepExisting (optional) true to keep existing selections
15936 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15938 select : function(nodeInfo, keepExisting, suppressEvent){
15939 if(nodeInfo instanceof Array){
15941 this.clearSelections(true);
15943 for(var i = 0, len = nodeInfo.length; i < len; i++){
15944 this.select(nodeInfo[i], true, true);
15948 var node = this.getNode(nodeInfo);
15949 if(!node || this.isSelected(node)){
15950 return; // already selected.
15953 this.clearSelections(true);
15956 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15957 Roo.fly(node).addClass(this.selectedClass);
15958 this.selections.push(node);
15959 if(!suppressEvent){
15960 this.fireEvent("selectionchange", this, this.selections);
15968 * @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
15969 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15970 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15972 unselect : function(nodeInfo, keepExisting, suppressEvent)
15974 if(nodeInfo instanceof Array){
15975 Roo.each(this.selections, function(s) {
15976 this.unselect(s, nodeInfo);
15980 var node = this.getNode(nodeInfo);
15981 if(!node || !this.isSelected(node)){
15982 //Roo.log("not selected");
15983 return; // not selected.
15987 Roo.each(this.selections, function(s) {
15989 Roo.fly(node).removeClass(this.selectedClass);
15996 this.selections= ns;
15997 this.fireEvent("selectionchange", this, this.selections);
16001 * Gets a template node.
16002 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16003 * @return {HTMLElement} The node or null if it wasn't found
16005 getNode : function(nodeInfo){
16006 if(typeof nodeInfo == "string"){
16007 return document.getElementById(nodeInfo);
16008 }else if(typeof nodeInfo == "number"){
16009 return this.nodes[nodeInfo];
16015 * Gets a range template nodes.
16016 * @param {Number} startIndex
16017 * @param {Number} endIndex
16018 * @return {Array} An array of nodes
16020 getNodes : function(start, end){
16021 var ns = this.nodes;
16022 start = start || 0;
16023 end = typeof end == "undefined" ? ns.length - 1 : end;
16026 for(var i = start; i <= end; i++){
16030 for(var i = start; i >= end; i--){
16038 * Finds the index of the passed node
16039 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16040 * @return {Number} The index of the node or -1
16042 indexOf : function(node){
16043 node = this.getNode(node);
16044 if(typeof node.nodeIndex == "number"){
16045 return node.nodeIndex;
16047 var ns = this.nodes;
16048 for(var i = 0, len = ns.length; i < len; i++){
16059 * based on jquery fullcalendar
16063 Roo.bootstrap = Roo.bootstrap || {};
16065 * @class Roo.bootstrap.Calendar
16066 * @extends Roo.bootstrap.Component
16067 * Bootstrap Calendar class
16068 * @cfg {Boolean} loadMask (true|false) default false
16069 * @cfg {Object} header generate the user specific header of the calendar, default false
16072 * Create a new Container
16073 * @param {Object} config The config object
16078 Roo.bootstrap.Calendar = function(config){
16079 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16083 * Fires when a date is selected
16084 * @param {DatePicker} this
16085 * @param {Date} date The selected date
16089 * @event monthchange
16090 * Fires when the displayed month changes
16091 * @param {DatePicker} this
16092 * @param {Date} date The selected month
16094 'monthchange': true,
16096 * @event evententer
16097 * Fires when mouse over an event
16098 * @param {Calendar} this
16099 * @param {event} Event
16101 'evententer': true,
16103 * @event eventleave
16104 * Fires when the mouse leaves an
16105 * @param {Calendar} this
16108 'eventleave': true,
16110 * @event eventclick
16111 * Fires when the mouse click an
16112 * @param {Calendar} this
16121 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16124 * @cfg {Number} startDay
16125 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16133 getAutoCreate : function(){
16136 var fc_button = function(name, corner, style, content ) {
16137 return Roo.apply({},{
16139 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16141 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16144 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16155 style : 'width:100%',
16162 cls : 'fc-header-left',
16164 fc_button('prev', 'left', 'arrow', '‹' ),
16165 fc_button('next', 'right', 'arrow', '›' ),
16166 { tag: 'span', cls: 'fc-header-space' },
16167 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16175 cls : 'fc-header-center',
16179 cls: 'fc-header-title',
16182 html : 'month / year'
16190 cls : 'fc-header-right',
16192 /* fc_button('month', 'left', '', 'month' ),
16193 fc_button('week', '', '', 'week' ),
16194 fc_button('day', 'right', '', 'day' )
16206 header = this.header;
16209 var cal_heads = function() {
16211 // fixme - handle this.
16213 for (var i =0; i < Date.dayNames.length; i++) {
16214 var d = Date.dayNames[i];
16217 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16218 html : d.substring(0,3)
16222 ret[0].cls += ' fc-first';
16223 ret[6].cls += ' fc-last';
16226 var cal_cell = function(n) {
16229 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16234 cls: 'fc-day-number',
16238 cls: 'fc-day-content',
16242 style: 'position: relative;' // height: 17px;
16254 var cal_rows = function() {
16257 for (var r = 0; r < 6; r++) {
16264 for (var i =0; i < Date.dayNames.length; i++) {
16265 var d = Date.dayNames[i];
16266 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16269 row.cn[0].cls+=' fc-first';
16270 row.cn[0].cn[0].style = 'min-height:90px';
16271 row.cn[6].cls+=' fc-last';
16275 ret[0].cls += ' fc-first';
16276 ret[4].cls += ' fc-prev-last';
16277 ret[5].cls += ' fc-last';
16284 cls: 'fc-border-separate',
16285 style : 'width:100%',
16293 cls : 'fc-first fc-last',
16311 cls : 'fc-content',
16312 style : "position: relative;",
16315 cls : 'fc-view fc-view-month fc-grid',
16316 style : 'position: relative',
16317 unselectable : 'on',
16320 cls : 'fc-event-container',
16321 style : 'position:absolute;z-index:8;top:0;left:0;'
16339 initEvents : function()
16342 throw "can not find store for calendar";
16348 style: "text-align:center",
16352 style: "background-color:white;width:50%;margin:250 auto",
16356 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16367 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16369 var size = this.el.select('.fc-content', true).first().getSize();
16370 this.maskEl.setSize(size.width, size.height);
16371 this.maskEl.enableDisplayMode("block");
16372 if(!this.loadMask){
16373 this.maskEl.hide();
16376 this.store = Roo.factory(this.store, Roo.data);
16377 this.store.on('load', this.onLoad, this);
16378 this.store.on('beforeload', this.onBeforeLoad, this);
16382 this.cells = this.el.select('.fc-day',true);
16383 //Roo.log(this.cells);
16384 this.textNodes = this.el.query('.fc-day-number');
16385 this.cells.addClassOnOver('fc-state-hover');
16387 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16388 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16389 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16390 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16392 this.on('monthchange', this.onMonthChange, this);
16394 this.update(new Date().clearTime());
16397 resize : function() {
16398 var sz = this.el.getSize();
16400 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16401 this.el.select('.fc-day-content div',true).setHeight(34);
16406 showPrevMonth : function(e){
16407 this.update(this.activeDate.add("mo", -1));
16409 showToday : function(e){
16410 this.update(new Date().clearTime());
16413 showNextMonth : function(e){
16414 this.update(this.activeDate.add("mo", 1));
16418 showPrevYear : function(){
16419 this.update(this.activeDate.add("y", -1));
16423 showNextYear : function(){
16424 this.update(this.activeDate.add("y", 1));
16429 update : function(date)
16431 var vd = this.activeDate;
16432 this.activeDate = date;
16433 // if(vd && this.el){
16434 // var t = date.getTime();
16435 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16436 // Roo.log('using add remove');
16438 // this.fireEvent('monthchange', this, date);
16440 // this.cells.removeClass("fc-state-highlight");
16441 // this.cells.each(function(c){
16442 // if(c.dateValue == t){
16443 // c.addClass("fc-state-highlight");
16444 // setTimeout(function(){
16445 // try{c.dom.firstChild.focus();}catch(e){}
16455 var days = date.getDaysInMonth();
16457 var firstOfMonth = date.getFirstDateOfMonth();
16458 var startingPos = firstOfMonth.getDay()-this.startDay;
16460 if(startingPos < this.startDay){
16464 var pm = date.add(Date.MONTH, -1);
16465 var prevStart = pm.getDaysInMonth()-startingPos;
16467 this.cells = this.el.select('.fc-day',true);
16468 this.textNodes = this.el.query('.fc-day-number');
16469 this.cells.addClassOnOver('fc-state-hover');
16471 var cells = this.cells.elements;
16472 var textEls = this.textNodes;
16474 Roo.each(cells, function(cell){
16475 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16478 days += startingPos;
16480 // convert everything to numbers so it's fast
16481 var day = 86400000;
16482 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16485 //Roo.log(prevStart);
16487 var today = new Date().clearTime().getTime();
16488 var sel = date.clearTime().getTime();
16489 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16490 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16491 var ddMatch = this.disabledDatesRE;
16492 var ddText = this.disabledDatesText;
16493 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16494 var ddaysText = this.disabledDaysText;
16495 var format = this.format;
16497 var setCellClass = function(cal, cell){
16501 //Roo.log('set Cell Class');
16503 var t = d.getTime();
16507 cell.dateValue = t;
16509 cell.className += " fc-today";
16510 cell.className += " fc-state-highlight";
16511 cell.title = cal.todayText;
16514 // disable highlight in other month..
16515 //cell.className += " fc-state-highlight";
16520 cell.className = " fc-state-disabled";
16521 cell.title = cal.minText;
16525 cell.className = " fc-state-disabled";
16526 cell.title = cal.maxText;
16530 if(ddays.indexOf(d.getDay()) != -1){
16531 cell.title = ddaysText;
16532 cell.className = " fc-state-disabled";
16535 if(ddMatch && format){
16536 var fvalue = d.dateFormat(format);
16537 if(ddMatch.test(fvalue)){
16538 cell.title = ddText.replace("%0", fvalue);
16539 cell.className = " fc-state-disabled";
16543 if (!cell.initialClassName) {
16544 cell.initialClassName = cell.dom.className;
16547 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16552 for(; i < startingPos; i++) {
16553 textEls[i].innerHTML = (++prevStart);
16554 d.setDate(d.getDate()+1);
16556 cells[i].className = "fc-past fc-other-month";
16557 setCellClass(this, cells[i]);
16562 for(; i < days; i++){
16563 intDay = i - startingPos + 1;
16564 textEls[i].innerHTML = (intDay);
16565 d.setDate(d.getDate()+1);
16567 cells[i].className = ''; // "x-date-active";
16568 setCellClass(this, cells[i]);
16572 for(; i < 42; i++) {
16573 textEls[i].innerHTML = (++extraDays);
16574 d.setDate(d.getDate()+1);
16576 cells[i].className = "fc-future fc-other-month";
16577 setCellClass(this, cells[i]);
16580 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16582 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16584 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16585 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16587 if(totalRows != 6){
16588 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16589 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16592 this.fireEvent('monthchange', this, date);
16596 if(!this.internalRender){
16597 var main = this.el.dom.firstChild;
16598 var w = main.offsetWidth;
16599 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16600 Roo.fly(main).setWidth(w);
16601 this.internalRender = true;
16602 // opera does not respect the auto grow header center column
16603 // then, after it gets a width opera refuses to recalculate
16604 // without a second pass
16605 if(Roo.isOpera && !this.secondPass){
16606 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16607 this.secondPass = true;
16608 this.update.defer(10, this, [date]);
16615 findCell : function(dt) {
16616 dt = dt.clearTime().getTime();
16618 this.cells.each(function(c){
16619 //Roo.log("check " +c.dateValue + '?=' + dt);
16620 if(c.dateValue == dt){
16630 findCells : function(ev) {
16631 var s = ev.start.clone().clearTime().getTime();
16633 var e= ev.end.clone().clearTime().getTime();
16636 this.cells.each(function(c){
16637 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16639 if(c.dateValue > e){
16642 if(c.dateValue < s){
16651 // findBestRow: function(cells)
16655 // for (var i =0 ; i < cells.length;i++) {
16656 // ret = Math.max(cells[i].rows || 0,ret);
16663 addItem : function(ev)
16665 // look for vertical location slot in
16666 var cells = this.findCells(ev);
16668 // ev.row = this.findBestRow(cells);
16670 // work out the location.
16674 for(var i =0; i < cells.length; i++) {
16676 cells[i].row = cells[0].row;
16679 cells[i].row = cells[i].row + 1;
16689 if (crow.start.getY() == cells[i].getY()) {
16691 crow.end = cells[i];
16708 cells[0].events.push(ev);
16710 this.calevents.push(ev);
16713 clearEvents: function() {
16715 if(!this.calevents){
16719 Roo.each(this.cells.elements, function(c){
16725 Roo.each(this.calevents, function(e) {
16726 Roo.each(e.els, function(el) {
16727 el.un('mouseenter' ,this.onEventEnter, this);
16728 el.un('mouseleave' ,this.onEventLeave, this);
16733 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16739 renderEvents: function()
16743 this.cells.each(function(c) {
16752 if(c.row != c.events.length){
16753 r = 4 - (4 - (c.row - c.events.length));
16756 c.events = ev.slice(0, r);
16757 c.more = ev.slice(r);
16759 if(c.more.length && c.more.length == 1){
16760 c.events.push(c.more.pop());
16763 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16767 this.cells.each(function(c) {
16769 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16772 for (var e = 0; e < c.events.length; e++){
16773 var ev = c.events[e];
16774 var rows = ev.rows;
16776 for(var i = 0; i < rows.length; i++) {
16778 // how many rows should it span..
16781 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16782 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16784 unselectable : "on",
16787 cls: 'fc-event-inner',
16791 // cls: 'fc-event-time',
16792 // html : cells.length > 1 ? '' : ev.time
16796 cls: 'fc-event-title',
16797 html : String.format('{0}', ev.title)
16804 cls: 'ui-resizable-handle ui-resizable-e',
16805 html : '  '
16812 cfg.cls += ' fc-event-start';
16814 if ((i+1) == rows.length) {
16815 cfg.cls += ' fc-event-end';
16818 var ctr = _this.el.select('.fc-event-container',true).first();
16819 var cg = ctr.createChild(cfg);
16821 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16822 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16824 var r = (c.more.length) ? 1 : 0;
16825 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16826 cg.setWidth(ebox.right - sbox.x -2);
16828 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16829 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16830 cg.on('click', _this.onEventClick, _this, ev);
16841 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16842 style : 'position: absolute',
16843 unselectable : "on",
16846 cls: 'fc-event-inner',
16850 cls: 'fc-event-title',
16858 cls: 'ui-resizable-handle ui-resizable-e',
16859 html : '  '
16865 var ctr = _this.el.select('.fc-event-container',true).first();
16866 var cg = ctr.createChild(cfg);
16868 var sbox = c.select('.fc-day-content',true).first().getBox();
16869 var ebox = c.select('.fc-day-content',true).first().getBox();
16871 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16872 cg.setWidth(ebox.right - sbox.x -2);
16874 cg.on('click', _this.onMoreEventClick, _this, c.more);
16884 onEventEnter: function (e, el,event,d) {
16885 this.fireEvent('evententer', this, el, event);
16888 onEventLeave: function (e, el,event,d) {
16889 this.fireEvent('eventleave', this, el, event);
16892 onEventClick: function (e, el,event,d) {
16893 this.fireEvent('eventclick', this, el, event);
16896 onMonthChange: function () {
16900 onMoreEventClick: function(e, el, more)
16904 this.calpopover.placement = 'right';
16905 this.calpopover.setTitle('More');
16907 this.calpopover.setContent('');
16909 var ctr = this.calpopover.el.select('.popover-content', true).first();
16911 Roo.each(more, function(m){
16913 cls : 'fc-event-hori fc-event-draggable',
16916 var cg = ctr.createChild(cfg);
16918 cg.on('click', _this.onEventClick, _this, m);
16921 this.calpopover.show(el);
16926 onLoad: function ()
16928 this.calevents = [];
16931 if(this.store.getCount() > 0){
16932 this.store.data.each(function(d){
16935 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16936 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16937 time : d.data.start_time,
16938 title : d.data.title,
16939 description : d.data.description,
16940 venue : d.data.venue
16945 this.renderEvents();
16947 if(this.calevents.length && this.loadMask){
16948 this.maskEl.hide();
16952 onBeforeLoad: function()
16954 this.clearEvents();
16956 this.maskEl.show();
16970 * @class Roo.bootstrap.Popover
16971 * @extends Roo.bootstrap.Component
16972 * Bootstrap Popover class
16973 * @cfg {String} html contents of the popover (or false to use children..)
16974 * @cfg {String} title of popover (or false to hide)
16975 * @cfg {String} placement how it is placed
16976 * @cfg {String} trigger click || hover (or false to trigger manually)
16977 * @cfg {String} over what (parent or false to trigger manually.)
16978 * @cfg {Number} delay - delay before showing
16981 * Create a new Popover
16982 * @param {Object} config The config object
16985 Roo.bootstrap.Popover = function(config){
16986 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16992 * After the popover show
16994 * @param {Roo.bootstrap.Popover} this
16999 * After the popover hide
17001 * @param {Roo.bootstrap.Popover} this
17007 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17009 title: 'Fill in a title',
17012 placement : 'right',
17013 trigger : 'hover', // hover
17019 can_build_overlaid : false,
17021 getChildContainer : function()
17023 return this.el.select('.popover-content',true).first();
17026 getAutoCreate : function(){
17029 cls : 'popover roo-dynamic',
17030 style: 'display:block',
17036 cls : 'popover-inner',
17040 cls: 'popover-title',
17044 cls : 'popover-content',
17055 setTitle: function(str)
17058 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17060 setContent: function(str)
17063 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17065 // as it get's added to the bottom of the page.
17066 onRender : function(ct, position)
17068 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17070 var cfg = Roo.apply({}, this.getAutoCreate());
17074 cfg.cls += ' ' + this.cls;
17077 cfg.style = this.style;
17079 //Roo.log("adding to ");
17080 this.el = Roo.get(document.body).createChild(cfg, position);
17081 // Roo.log(this.el);
17086 initEvents : function()
17088 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17089 this.el.enableDisplayMode('block');
17091 if (this.over === false) {
17094 if (this.triggers === false) {
17097 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17098 var triggers = this.trigger ? this.trigger.split(' ') : [];
17099 Roo.each(triggers, function(trigger) {
17101 if (trigger == 'click') {
17102 on_el.on('click', this.toggle, this);
17103 } else if (trigger != 'manual') {
17104 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17105 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17107 on_el.on(eventIn ,this.enter, this);
17108 on_el.on(eventOut, this.leave, this);
17119 toggle : function () {
17120 this.hoverState == 'in' ? this.leave() : this.enter();
17123 enter : function () {
17125 clearTimeout(this.timeout);
17127 this.hoverState = 'in';
17129 if (!this.delay || !this.delay.show) {
17134 this.timeout = setTimeout(function () {
17135 if (_t.hoverState == 'in') {
17138 }, this.delay.show)
17141 leave : function() {
17142 clearTimeout(this.timeout);
17144 this.hoverState = 'out';
17146 if (!this.delay || !this.delay.hide) {
17151 this.timeout = setTimeout(function () {
17152 if (_t.hoverState == 'out') {
17155 }, this.delay.hide)
17158 show : function (on_el)
17161 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17165 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17166 if (this.html !== false) {
17167 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17169 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17170 if (!this.title.length) {
17171 this.el.select('.popover-title',true).hide();
17174 var placement = typeof this.placement == 'function' ?
17175 this.placement.call(this, this.el, on_el) :
17178 var autoToken = /\s?auto?\s?/i;
17179 var autoPlace = autoToken.test(placement);
17181 placement = placement.replace(autoToken, '') || 'top';
17185 //this.el.setXY([0,0]);
17187 this.el.dom.style.display='block';
17188 this.el.addClass(placement);
17190 //this.el.appendTo(on_el);
17192 var p = this.getPosition();
17193 var box = this.el.getBox();
17198 var align = Roo.bootstrap.Popover.alignment[placement];
17199 this.el.alignTo(on_el, align[0],align[1]);
17200 //var arrow = this.el.select('.arrow',true).first();
17201 //arrow.set(align[2],
17203 this.el.addClass('in');
17206 if (this.el.hasClass('fade')) {
17210 this.hoverState = 'in';
17212 this.fireEvent('show', this);
17217 this.el.setXY([0,0]);
17218 this.el.removeClass('in');
17220 this.hoverState = null;
17222 this.fireEvent('hide', this);
17227 Roo.bootstrap.Popover.alignment = {
17228 'left' : ['r-l', [-10,0], 'right'],
17229 'right' : ['l-r', [10,0], 'left'],
17230 'bottom' : ['t-b', [0,10], 'top'],
17231 'top' : [ 'b-t', [0,-10], 'bottom']
17242 * @class Roo.bootstrap.Progress
17243 * @extends Roo.bootstrap.Component
17244 * Bootstrap Progress class
17245 * @cfg {Boolean} striped striped of the progress bar
17246 * @cfg {Boolean} active animated of the progress bar
17250 * Create a new Progress
17251 * @param {Object} config The config object
17254 Roo.bootstrap.Progress = function(config){
17255 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17258 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17263 getAutoCreate : function(){
17271 cfg.cls += ' progress-striped';
17275 cfg.cls += ' active';
17294 * @class Roo.bootstrap.ProgressBar
17295 * @extends Roo.bootstrap.Component
17296 * Bootstrap ProgressBar class
17297 * @cfg {Number} aria_valuenow aria-value now
17298 * @cfg {Number} aria_valuemin aria-value min
17299 * @cfg {Number} aria_valuemax aria-value max
17300 * @cfg {String} label label for the progress bar
17301 * @cfg {String} panel (success | info | warning | danger )
17302 * @cfg {String} role role of the progress bar
17303 * @cfg {String} sr_only text
17307 * Create a new ProgressBar
17308 * @param {Object} config The config object
17311 Roo.bootstrap.ProgressBar = function(config){
17312 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17315 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17319 aria_valuemax : 100,
17325 getAutoCreate : function()
17330 cls: 'progress-bar',
17331 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17343 cfg.role = this.role;
17346 if(this.aria_valuenow){
17347 cfg['aria-valuenow'] = this.aria_valuenow;
17350 if(this.aria_valuemin){
17351 cfg['aria-valuemin'] = this.aria_valuemin;
17354 if(this.aria_valuemax){
17355 cfg['aria-valuemax'] = this.aria_valuemax;
17358 if(this.label && !this.sr_only){
17359 cfg.html = this.label;
17363 cfg.cls += ' progress-bar-' + this.panel;
17369 update : function(aria_valuenow)
17371 this.aria_valuenow = aria_valuenow;
17373 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17388 * @class Roo.bootstrap.TabGroup
17389 * @extends Roo.bootstrap.Column
17390 * Bootstrap Column class
17391 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17392 * @cfg {Boolean} carousel true to make the group behave like a carousel
17393 * @cfg {Boolean} bullets show bullets for the panels
17394 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17395 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17396 * @cfg {Boolean} showarrow (true|false) show arrow default true
17399 * Create a new TabGroup
17400 * @param {Object} config The config object
17403 Roo.bootstrap.TabGroup = function(config){
17404 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17406 this.navId = Roo.id();
17409 Roo.bootstrap.TabGroup.register(this);
17413 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17416 transition : false,
17421 slideOnTouch : false,
17424 getAutoCreate : function()
17426 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17428 cfg.cls += ' tab-content';
17430 if (this.carousel) {
17431 cfg.cls += ' carousel slide';
17434 cls : 'carousel-inner',
17438 if(this.bullets && !Roo.isTouch){
17441 cls : 'carousel-bullets',
17445 if(this.bullets_cls){
17446 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17453 cfg.cn[0].cn.push(bullets);
17456 if(this.showarrow){
17457 cfg.cn[0].cn.push({
17459 class : 'carousel-arrow',
17463 class : 'carousel-prev',
17467 class : 'fa fa-chevron-left'
17473 class : 'carousel-next',
17477 class : 'fa fa-chevron-right'
17490 initEvents: function()
17492 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17493 // this.el.on("touchstart", this.onTouchStart, this);
17496 if(this.autoslide){
17499 this.slideFn = window.setInterval(function() {
17500 _this.showPanelNext();
17504 if(this.showarrow){
17505 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17506 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17512 // onTouchStart : function(e, el, o)
17514 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17518 // this.showPanelNext();
17522 getChildContainer : function()
17524 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17528 * register a Navigation item
17529 * @param {Roo.bootstrap.NavItem} the navitem to add
17531 register : function(item)
17533 this.tabs.push( item);
17534 item.navId = this.navId; // not really needed..
17539 getActivePanel : function()
17542 Roo.each(this.tabs, function(t) {
17552 getPanelByName : function(n)
17555 Roo.each(this.tabs, function(t) {
17556 if (t.tabId == n) {
17564 indexOfPanel : function(p)
17567 Roo.each(this.tabs, function(t,i) {
17568 if (t.tabId == p.tabId) {
17577 * show a specific panel
17578 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17579 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17581 showPanel : function (pan)
17583 if(this.transition || typeof(pan) == 'undefined'){
17584 Roo.log("waiting for the transitionend");
17588 if (typeof(pan) == 'number') {
17589 pan = this.tabs[pan];
17592 if (typeof(pan) == 'string') {
17593 pan = this.getPanelByName(pan);
17596 var cur = this.getActivePanel();
17599 Roo.log('pan or acitve pan is undefined');
17603 if (pan.tabId == this.getActivePanel().tabId) {
17607 if (false === cur.fireEvent('beforedeactivate')) {
17611 if(this.bullets > 0 && !Roo.isTouch){
17612 this.setActiveBullet(this.indexOfPanel(pan));
17615 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17617 this.transition = true;
17618 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17619 var lr = dir == 'next' ? 'left' : 'right';
17620 pan.el.addClass(dir); // or prev
17621 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17622 cur.el.addClass(lr); // or right
17623 pan.el.addClass(lr);
17626 cur.el.on('transitionend', function() {
17627 Roo.log("trans end?");
17629 pan.el.removeClass([lr,dir]);
17630 pan.setActive(true);
17632 cur.el.removeClass([lr]);
17633 cur.setActive(false);
17635 _this.transition = false;
17637 }, this, { single: true } );
17642 cur.setActive(false);
17643 pan.setActive(true);
17648 showPanelNext : function()
17650 var i = this.indexOfPanel(this.getActivePanel());
17652 if (i >= this.tabs.length - 1 && !this.autoslide) {
17656 if (i >= this.tabs.length - 1 && this.autoslide) {
17660 this.showPanel(this.tabs[i+1]);
17663 showPanelPrev : function()
17665 var i = this.indexOfPanel(this.getActivePanel());
17667 if (i < 1 && !this.autoslide) {
17671 if (i < 1 && this.autoslide) {
17672 i = this.tabs.length;
17675 this.showPanel(this.tabs[i-1]);
17679 addBullet: function()
17681 if(!this.bullets || Roo.isTouch){
17684 var ctr = this.el.select('.carousel-bullets',true).first();
17685 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17686 var bullet = ctr.createChild({
17687 cls : 'bullet bullet-' + i
17688 },ctr.dom.lastChild);
17693 bullet.on('click', (function(e, el, o, ii, t){
17695 e.preventDefault();
17697 this.showPanel(ii);
17699 if(this.autoslide && this.slideFn){
17700 clearInterval(this.slideFn);
17701 this.slideFn = window.setInterval(function() {
17702 _this.showPanelNext();
17706 }).createDelegate(this, [i, bullet], true));
17711 setActiveBullet : function(i)
17717 Roo.each(this.el.select('.bullet', true).elements, function(el){
17718 el.removeClass('selected');
17721 var bullet = this.el.select('.bullet-' + i, true).first();
17727 bullet.addClass('selected');
17738 Roo.apply(Roo.bootstrap.TabGroup, {
17742 * register a Navigation Group
17743 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17745 register : function(navgrp)
17747 this.groups[navgrp.navId] = navgrp;
17751 * fetch a Navigation Group based on the navigation ID
17752 * if one does not exist , it will get created.
17753 * @param {string} the navgroup to add
17754 * @returns {Roo.bootstrap.NavGroup} the navgroup
17756 get: function(navId) {
17757 if (typeof(this.groups[navId]) == 'undefined') {
17758 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17760 return this.groups[navId] ;
17775 * @class Roo.bootstrap.TabPanel
17776 * @extends Roo.bootstrap.Component
17777 * Bootstrap TabPanel class
17778 * @cfg {Boolean} active panel active
17779 * @cfg {String} html panel content
17780 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17781 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17782 * @cfg {String} href click to link..
17786 * Create a new TabPanel
17787 * @param {Object} config The config object
17790 Roo.bootstrap.TabPanel = function(config){
17791 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17795 * Fires when the active status changes
17796 * @param {Roo.bootstrap.TabPanel} this
17797 * @param {Boolean} state the new state
17802 * @event beforedeactivate
17803 * Fires before a tab is de-activated - can be used to do validation on a form.
17804 * @param {Roo.bootstrap.TabPanel} this
17805 * @return {Boolean} false if there is an error
17808 'beforedeactivate': true
17811 this.tabId = this.tabId || Roo.id();
17815 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17823 getAutoCreate : function(){
17826 // item is needed for carousel - not sure if it has any effect otherwise
17827 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17828 html: this.html || ''
17832 cfg.cls += ' active';
17836 cfg.tabId = this.tabId;
17843 initEvents: function()
17845 var p = this.parent();
17847 this.navId = this.navId || p.navId;
17849 if (typeof(this.navId) != 'undefined') {
17850 // not really needed.. but just in case.. parent should be a NavGroup.
17851 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17855 var i = tg.tabs.length - 1;
17857 if(this.active && tg.bullets > 0 && i < tg.bullets){
17858 tg.setActiveBullet(i);
17862 this.el.on('click', this.onClick, this);
17865 this.el.on("touchstart", this.onTouchStart, this);
17866 this.el.on("touchmove", this.onTouchMove, this);
17867 this.el.on("touchend", this.onTouchEnd, this);
17872 onRender : function(ct, position)
17874 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17877 setActive : function(state)
17879 Roo.log("panel - set active " + this.tabId + "=" + state);
17881 this.active = state;
17883 this.el.removeClass('active');
17885 } else if (!this.el.hasClass('active')) {
17886 this.el.addClass('active');
17889 this.fireEvent('changed', this, state);
17892 onClick : function(e)
17894 e.preventDefault();
17896 if(!this.href.length){
17900 window.location.href = this.href;
17909 onTouchStart : function(e)
17911 this.swiping = false;
17913 this.startX = e.browserEvent.touches[0].clientX;
17914 this.startY = e.browserEvent.touches[0].clientY;
17917 onTouchMove : function(e)
17919 this.swiping = true;
17921 this.endX = e.browserEvent.touches[0].clientX;
17922 this.endY = e.browserEvent.touches[0].clientY;
17925 onTouchEnd : function(e)
17932 var tabGroup = this.parent();
17934 if(this.endX > this.startX){ // swiping right
17935 tabGroup.showPanelPrev();
17939 if(this.startX > this.endX){ // swiping left
17940 tabGroup.showPanelNext();
17959 * @class Roo.bootstrap.DateField
17960 * @extends Roo.bootstrap.Input
17961 * Bootstrap DateField class
17962 * @cfg {Number} weekStart default 0
17963 * @cfg {String} viewMode default empty, (months|years)
17964 * @cfg {String} minViewMode default empty, (months|years)
17965 * @cfg {Number} startDate default -Infinity
17966 * @cfg {Number} endDate default Infinity
17967 * @cfg {Boolean} todayHighlight default false
17968 * @cfg {Boolean} todayBtn default false
17969 * @cfg {Boolean} calendarWeeks default false
17970 * @cfg {Object} daysOfWeekDisabled default empty
17971 * @cfg {Boolean} singleMode default false (true | false)
17973 * @cfg {Boolean} keyboardNavigation default true
17974 * @cfg {String} language default en
17977 * Create a new DateField
17978 * @param {Object} config The config object
17981 Roo.bootstrap.DateField = function(config){
17982 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17986 * Fires when this field show.
17987 * @param {Roo.bootstrap.DateField} this
17988 * @param {Mixed} date The date value
17993 * Fires when this field hide.
17994 * @param {Roo.bootstrap.DateField} this
17995 * @param {Mixed} date The date value
18000 * Fires when select a date.
18001 * @param {Roo.bootstrap.DateField} this
18002 * @param {Mixed} date The date value
18006 * @event beforeselect
18007 * Fires when before select a date.
18008 * @param {Roo.bootstrap.DateField} this
18009 * @param {Mixed} date The date value
18011 beforeselect : true
18015 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18018 * @cfg {String} format
18019 * The default date format string which can be overriden for localization support. The format must be
18020 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18024 * @cfg {String} altFormats
18025 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18026 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18028 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18036 todayHighlight : false,
18042 keyboardNavigation: true,
18044 calendarWeeks: false,
18046 startDate: -Infinity,
18050 daysOfWeekDisabled: [],
18054 singleMode : false,
18056 UTCDate: function()
18058 return new Date(Date.UTC.apply(Date, arguments));
18061 UTCToday: function()
18063 var today = new Date();
18064 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18067 getDate: function() {
18068 var d = this.getUTCDate();
18069 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18072 getUTCDate: function() {
18076 setDate: function(d) {
18077 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18080 setUTCDate: function(d) {
18082 this.setValue(this.formatDate(this.date));
18085 onRender: function(ct, position)
18088 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18090 this.language = this.language || 'en';
18091 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18092 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18094 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18095 this.format = this.format || 'm/d/y';
18096 this.isInline = false;
18097 this.isInput = true;
18098 this.component = this.el.select('.add-on', true).first() || false;
18099 this.component = (this.component && this.component.length === 0) ? false : this.component;
18100 this.hasInput = this.component && this.inputEl().length;
18102 if (typeof(this.minViewMode === 'string')) {
18103 switch (this.minViewMode) {
18105 this.minViewMode = 1;
18108 this.minViewMode = 2;
18111 this.minViewMode = 0;
18116 if (typeof(this.viewMode === 'string')) {
18117 switch (this.viewMode) {
18130 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18132 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18134 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18136 this.picker().on('mousedown', this.onMousedown, this);
18137 this.picker().on('click', this.onClick, this);
18139 this.picker().addClass('datepicker-dropdown');
18141 this.startViewMode = this.viewMode;
18143 if(this.singleMode){
18144 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18145 v.setVisibilityMode(Roo.Element.DISPLAY);
18149 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18150 v.setStyle('width', '189px');
18154 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18155 if(!this.calendarWeeks){
18160 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18161 v.attr('colspan', function(i, val){
18162 return parseInt(val) + 1;
18167 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18169 this.setStartDate(this.startDate);
18170 this.setEndDate(this.endDate);
18172 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18179 if(this.isInline) {
18184 picker : function()
18186 return this.pickerEl;
18187 // return this.el.select('.datepicker', true).first();
18190 fillDow: function()
18192 var dowCnt = this.weekStart;
18201 if(this.calendarWeeks){
18209 while (dowCnt < this.weekStart + 7) {
18213 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18217 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18220 fillMonths: function()
18223 var months = this.picker().select('>.datepicker-months td', true).first();
18225 months.dom.innerHTML = '';
18231 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18234 months.createChild(month);
18241 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;
18243 if (this.date < this.startDate) {
18244 this.viewDate = new Date(this.startDate);
18245 } else if (this.date > this.endDate) {
18246 this.viewDate = new Date(this.endDate);
18248 this.viewDate = new Date(this.date);
18256 var d = new Date(this.viewDate),
18257 year = d.getUTCFullYear(),
18258 month = d.getUTCMonth(),
18259 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18260 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18261 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18262 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18263 currentDate = this.date && this.date.valueOf(),
18264 today = this.UTCToday();
18266 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18268 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18270 // this.picker.select('>tfoot th.today').
18271 // .text(dates[this.language].today)
18272 // .toggle(this.todayBtn !== false);
18274 this.updateNavArrows();
18277 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18279 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18281 prevMonth.setUTCDate(day);
18283 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18285 var nextMonth = new Date(prevMonth);
18287 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18289 nextMonth = nextMonth.valueOf();
18291 var fillMonths = false;
18293 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18295 while(prevMonth.valueOf() < nextMonth) {
18298 if (prevMonth.getUTCDay() === this.weekStart) {
18300 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18308 if(this.calendarWeeks){
18309 // ISO 8601: First week contains first thursday.
18310 // ISO also states week starts on Monday, but we can be more abstract here.
18312 // Start of current week: based on weekstart/current date
18313 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18314 // Thursday of this week
18315 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18316 // First Thursday of year, year from thursday
18317 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18318 // Calendar week: ms between thursdays, div ms per day, div 7 days
18319 calWeek = (th - yth) / 864e5 / 7 + 1;
18321 fillMonths.cn.push({
18329 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18331 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18334 if (this.todayHighlight &&
18335 prevMonth.getUTCFullYear() == today.getFullYear() &&
18336 prevMonth.getUTCMonth() == today.getMonth() &&
18337 prevMonth.getUTCDate() == today.getDate()) {
18338 clsName += ' today';
18341 if (currentDate && prevMonth.valueOf() === currentDate) {
18342 clsName += ' active';
18345 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18346 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18347 clsName += ' disabled';
18350 fillMonths.cn.push({
18352 cls: 'day ' + clsName,
18353 html: prevMonth.getDate()
18356 prevMonth.setDate(prevMonth.getDate()+1);
18359 var currentYear = this.date && this.date.getUTCFullYear();
18360 var currentMonth = this.date && this.date.getUTCMonth();
18362 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18364 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18365 v.removeClass('active');
18367 if(currentYear === year && k === currentMonth){
18368 v.addClass('active');
18371 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18372 v.addClass('disabled');
18378 year = parseInt(year/10, 10) * 10;
18380 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18382 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18385 for (var i = -1; i < 11; i++) {
18386 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18388 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18396 showMode: function(dir)
18399 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18402 Roo.each(this.picker().select('>div',true).elements, function(v){
18403 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18406 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18411 if(this.isInline) {
18415 this.picker().removeClass(['bottom', 'top']);
18417 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18419 * place to the top of element!
18423 this.picker().addClass('top');
18424 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18429 this.picker().addClass('bottom');
18431 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18434 parseDate : function(value)
18436 if(!value || value instanceof Date){
18439 var v = Date.parseDate(value, this.format);
18440 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18441 v = Date.parseDate(value, 'Y-m-d');
18443 if(!v && this.altFormats){
18444 if(!this.altFormatsArray){
18445 this.altFormatsArray = this.altFormats.split("|");
18447 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18448 v = Date.parseDate(value, this.altFormatsArray[i]);
18454 formatDate : function(date, fmt)
18456 return (!date || !(date instanceof Date)) ?
18457 date : date.dateFormat(fmt || this.format);
18460 onFocus : function()
18462 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18466 onBlur : function()
18468 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18470 var d = this.inputEl().getValue();
18479 this.picker().show();
18483 this.fireEvent('show', this, this.date);
18488 if(this.isInline) {
18491 this.picker().hide();
18492 this.viewMode = this.startViewMode;
18495 this.fireEvent('hide', this, this.date);
18499 onMousedown: function(e)
18501 e.stopPropagation();
18502 e.preventDefault();
18507 Roo.bootstrap.DateField.superclass.keyup.call(this);
18511 setValue: function(v)
18513 if(this.fireEvent('beforeselect', this, v) !== false){
18514 var d = new Date(this.parseDate(v) ).clearTime();
18516 if(isNaN(d.getTime())){
18517 this.date = this.viewDate = '';
18518 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18522 v = this.formatDate(d);
18524 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18526 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18530 this.fireEvent('select', this, this.date);
18534 getValue: function()
18536 return this.formatDate(this.date);
18539 fireKey: function(e)
18541 if (!this.picker().isVisible()){
18542 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18548 var dateChanged = false,
18550 newDate, newViewDate;
18555 e.preventDefault();
18559 if (!this.keyboardNavigation) {
18562 dir = e.keyCode == 37 ? -1 : 1;
18565 newDate = this.moveYear(this.date, dir);
18566 newViewDate = this.moveYear(this.viewDate, dir);
18567 } else if (e.shiftKey){
18568 newDate = this.moveMonth(this.date, dir);
18569 newViewDate = this.moveMonth(this.viewDate, dir);
18571 newDate = new Date(this.date);
18572 newDate.setUTCDate(this.date.getUTCDate() + dir);
18573 newViewDate = new Date(this.viewDate);
18574 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18576 if (this.dateWithinRange(newDate)){
18577 this.date = newDate;
18578 this.viewDate = newViewDate;
18579 this.setValue(this.formatDate(this.date));
18581 e.preventDefault();
18582 dateChanged = true;
18587 if (!this.keyboardNavigation) {
18590 dir = e.keyCode == 38 ? -1 : 1;
18592 newDate = this.moveYear(this.date, dir);
18593 newViewDate = this.moveYear(this.viewDate, dir);
18594 } else if (e.shiftKey){
18595 newDate = this.moveMonth(this.date, dir);
18596 newViewDate = this.moveMonth(this.viewDate, dir);
18598 newDate = new Date(this.date);
18599 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18600 newViewDate = new Date(this.viewDate);
18601 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18603 if (this.dateWithinRange(newDate)){
18604 this.date = newDate;
18605 this.viewDate = newViewDate;
18606 this.setValue(this.formatDate(this.date));
18608 e.preventDefault();
18609 dateChanged = true;
18613 this.setValue(this.formatDate(this.date));
18615 e.preventDefault();
18618 this.setValue(this.formatDate(this.date));
18632 onClick: function(e)
18634 e.stopPropagation();
18635 e.preventDefault();
18637 var target = e.getTarget();
18639 if(target.nodeName.toLowerCase() === 'i'){
18640 target = Roo.get(target).dom.parentNode;
18643 var nodeName = target.nodeName;
18644 var className = target.className;
18645 var html = target.innerHTML;
18646 //Roo.log(nodeName);
18648 switch(nodeName.toLowerCase()) {
18650 switch(className) {
18656 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18657 switch(this.viewMode){
18659 this.viewDate = this.moveMonth(this.viewDate, dir);
18663 this.viewDate = this.moveYear(this.viewDate, dir);
18669 var date = new Date();
18670 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18672 this.setValue(this.formatDate(this.date));
18679 if (className.indexOf('disabled') < 0) {
18680 this.viewDate.setUTCDate(1);
18681 if (className.indexOf('month') > -1) {
18682 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18684 var year = parseInt(html, 10) || 0;
18685 this.viewDate.setUTCFullYear(year);
18689 if(this.singleMode){
18690 this.setValue(this.formatDate(this.viewDate));
18701 //Roo.log(className);
18702 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18703 var day = parseInt(html, 10) || 1;
18704 var year = this.viewDate.getUTCFullYear(),
18705 month = this.viewDate.getUTCMonth();
18707 if (className.indexOf('old') > -1) {
18714 } else if (className.indexOf('new') > -1) {
18722 //Roo.log([year,month,day]);
18723 this.date = this.UTCDate(year, month, day,0,0,0,0);
18724 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18726 //Roo.log(this.formatDate(this.date));
18727 this.setValue(this.formatDate(this.date));
18734 setStartDate: function(startDate)
18736 this.startDate = startDate || -Infinity;
18737 if (this.startDate !== -Infinity) {
18738 this.startDate = this.parseDate(this.startDate);
18741 this.updateNavArrows();
18744 setEndDate: function(endDate)
18746 this.endDate = endDate || Infinity;
18747 if (this.endDate !== Infinity) {
18748 this.endDate = this.parseDate(this.endDate);
18751 this.updateNavArrows();
18754 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18756 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18757 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18758 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18760 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18761 return parseInt(d, 10);
18764 this.updateNavArrows();
18767 updateNavArrows: function()
18769 if(this.singleMode){
18773 var d = new Date(this.viewDate),
18774 year = d.getUTCFullYear(),
18775 month = d.getUTCMonth();
18777 Roo.each(this.picker().select('.prev', true).elements, function(v){
18779 switch (this.viewMode) {
18782 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18788 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18795 Roo.each(this.picker().select('.next', true).elements, function(v){
18797 switch (this.viewMode) {
18800 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18806 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18814 moveMonth: function(date, dir)
18819 var new_date = new Date(date.valueOf()),
18820 day = new_date.getUTCDate(),
18821 month = new_date.getUTCMonth(),
18822 mag = Math.abs(dir),
18824 dir = dir > 0 ? 1 : -1;
18827 // If going back one month, make sure month is not current month
18828 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18830 return new_date.getUTCMonth() == month;
18832 // If going forward one month, make sure month is as expected
18833 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18835 return new_date.getUTCMonth() != new_month;
18837 new_month = month + dir;
18838 new_date.setUTCMonth(new_month);
18839 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18840 if (new_month < 0 || new_month > 11) {
18841 new_month = (new_month + 12) % 12;
18844 // For magnitudes >1, move one month at a time...
18845 for (var i=0; i<mag; i++) {
18846 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18847 new_date = this.moveMonth(new_date, dir);
18849 // ...then reset the day, keeping it in the new month
18850 new_month = new_date.getUTCMonth();
18851 new_date.setUTCDate(day);
18853 return new_month != new_date.getUTCMonth();
18856 // Common date-resetting loop -- if date is beyond end of month, make it
18859 new_date.setUTCDate(--day);
18860 new_date.setUTCMonth(new_month);
18865 moveYear: function(date, dir)
18867 return this.moveMonth(date, dir*12);
18870 dateWithinRange: function(date)
18872 return date >= this.startDate && date <= this.endDate;
18878 this.picker().remove();
18881 validateValue : function(value)
18883 if(value.length < 1) {
18884 if(this.allowBlank){
18890 if(value.length < this.minLength){
18893 if(value.length > this.maxLength){
18897 var vt = Roo.form.VTypes;
18898 if(!vt[this.vtype](value, this)){
18902 if(typeof this.validator == "function"){
18903 var msg = this.validator(value);
18909 if(this.regex && !this.regex.test(value)){
18913 if(typeof(this.parseDate(value)) == 'undefined'){
18917 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18921 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18931 Roo.apply(Roo.bootstrap.DateField, {
18942 html: '<i class="fa fa-arrow-left"/>'
18952 html: '<i class="fa fa-arrow-right"/>'
18994 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18995 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18996 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18997 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18998 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19011 navFnc: 'FullYear',
19016 navFnc: 'FullYear',
19021 Roo.apply(Roo.bootstrap.DateField, {
19025 cls: 'datepicker dropdown-menu roo-dynamic',
19029 cls: 'datepicker-days',
19033 cls: 'table-condensed',
19035 Roo.bootstrap.DateField.head,
19039 Roo.bootstrap.DateField.footer
19046 cls: 'datepicker-months',
19050 cls: 'table-condensed',
19052 Roo.bootstrap.DateField.head,
19053 Roo.bootstrap.DateField.content,
19054 Roo.bootstrap.DateField.footer
19061 cls: 'datepicker-years',
19065 cls: 'table-condensed',
19067 Roo.bootstrap.DateField.head,
19068 Roo.bootstrap.DateField.content,
19069 Roo.bootstrap.DateField.footer
19088 * @class Roo.bootstrap.TimeField
19089 * @extends Roo.bootstrap.Input
19090 * Bootstrap DateField class
19094 * Create a new TimeField
19095 * @param {Object} config The config object
19098 Roo.bootstrap.TimeField = function(config){
19099 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19103 * Fires when this field show.
19104 * @param {Roo.bootstrap.DateField} thisthis
19105 * @param {Mixed} date The date value
19110 * Fires when this field hide.
19111 * @param {Roo.bootstrap.DateField} this
19112 * @param {Mixed} date The date value
19117 * Fires when select a date.
19118 * @param {Roo.bootstrap.DateField} this
19119 * @param {Mixed} date The date value
19125 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19128 * @cfg {String} format
19129 * The default time format string which can be overriden for localization support. The format must be
19130 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19134 onRender: function(ct, position)
19137 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19139 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19141 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19143 this.pop = this.picker().select('>.datepicker-time',true).first();
19144 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19146 this.picker().on('mousedown', this.onMousedown, this);
19147 this.picker().on('click', this.onClick, this);
19149 this.picker().addClass('datepicker-dropdown');
19154 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19155 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19156 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19157 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19158 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19159 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19163 fireKey: function(e){
19164 if (!this.picker().isVisible()){
19165 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19171 e.preventDefault();
19179 this.onTogglePeriod();
19182 this.onIncrementMinutes();
19185 this.onDecrementMinutes();
19194 onClick: function(e) {
19195 e.stopPropagation();
19196 e.preventDefault();
19199 picker : function()
19201 return this.el.select('.datepicker', true).first();
19204 fillTime: function()
19206 var time = this.pop.select('tbody', true).first();
19208 time.dom.innerHTML = '';
19223 cls: 'hours-up glyphicon glyphicon-chevron-up'
19243 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19264 cls: 'timepicker-hour',
19279 cls: 'timepicker-minute',
19294 cls: 'btn btn-primary period',
19316 cls: 'hours-down glyphicon glyphicon-chevron-down'
19336 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19354 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19361 var hours = this.time.getHours();
19362 var minutes = this.time.getMinutes();
19375 hours = hours - 12;
19379 hours = '0' + hours;
19383 minutes = '0' + minutes;
19386 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19387 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19388 this.pop.select('button', true).first().dom.innerHTML = period;
19394 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19396 var cls = ['bottom'];
19398 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19405 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19410 this.picker().addClass(cls.join('-'));
19414 Roo.each(cls, function(c){
19416 _this.picker().setTop(_this.inputEl().getHeight());
19420 _this.picker().setTop(0 - _this.picker().getHeight());
19425 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19429 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19436 onFocus : function()
19438 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19442 onBlur : function()
19444 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19450 this.picker().show();
19455 this.fireEvent('show', this, this.date);
19460 this.picker().hide();
19463 this.fireEvent('hide', this, this.date);
19466 setTime : function()
19469 this.setValue(this.time.format(this.format));
19471 this.fireEvent('select', this, this.date);
19476 onMousedown: function(e){
19477 e.stopPropagation();
19478 e.preventDefault();
19481 onIncrementHours: function()
19483 Roo.log('onIncrementHours');
19484 this.time = this.time.add(Date.HOUR, 1);
19489 onDecrementHours: function()
19491 Roo.log('onDecrementHours');
19492 this.time = this.time.add(Date.HOUR, -1);
19496 onIncrementMinutes: function()
19498 Roo.log('onIncrementMinutes');
19499 this.time = this.time.add(Date.MINUTE, 1);
19503 onDecrementMinutes: function()
19505 Roo.log('onDecrementMinutes');
19506 this.time = this.time.add(Date.MINUTE, -1);
19510 onTogglePeriod: function()
19512 Roo.log('onTogglePeriod');
19513 this.time = this.time.add(Date.HOUR, 12);
19520 Roo.apply(Roo.bootstrap.TimeField, {
19550 cls: 'btn btn-info ok',
19562 Roo.apply(Roo.bootstrap.TimeField, {
19566 cls: 'datepicker dropdown-menu',
19570 cls: 'datepicker-time',
19574 cls: 'table-condensed',
19576 Roo.bootstrap.TimeField.content,
19577 Roo.bootstrap.TimeField.footer
19596 * @class Roo.bootstrap.MonthField
19597 * @extends Roo.bootstrap.Input
19598 * Bootstrap MonthField class
19600 * @cfg {String} language default en
19603 * Create a new MonthField
19604 * @param {Object} config The config object
19607 Roo.bootstrap.MonthField = function(config){
19608 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19613 * Fires when this field show.
19614 * @param {Roo.bootstrap.MonthField} this
19615 * @param {Mixed} date The date value
19620 * Fires when this field hide.
19621 * @param {Roo.bootstrap.MonthField} this
19622 * @param {Mixed} date The date value
19627 * Fires when select a date.
19628 * @param {Roo.bootstrap.MonthField} this
19629 * @param {String} oldvalue The old value
19630 * @param {String} newvalue The new value
19636 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19638 onRender: function(ct, position)
19641 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19643 this.language = this.language || 'en';
19644 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19645 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19647 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19648 this.isInline = false;
19649 this.isInput = true;
19650 this.component = this.el.select('.add-on', true).first() || false;
19651 this.component = (this.component && this.component.length === 0) ? false : this.component;
19652 this.hasInput = this.component && this.inputEL().length;
19654 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19656 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19658 this.picker().on('mousedown', this.onMousedown, this);
19659 this.picker().on('click', this.onClick, this);
19661 this.picker().addClass('datepicker-dropdown');
19663 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19664 v.setStyle('width', '189px');
19671 if(this.isInline) {
19677 setValue: function(v, suppressEvent)
19679 var o = this.getValue();
19681 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19685 if(suppressEvent !== true){
19686 this.fireEvent('select', this, o, v);
19691 getValue: function()
19696 onClick: function(e)
19698 e.stopPropagation();
19699 e.preventDefault();
19701 var target = e.getTarget();
19703 if(target.nodeName.toLowerCase() === 'i'){
19704 target = Roo.get(target).dom.parentNode;
19707 var nodeName = target.nodeName;
19708 var className = target.className;
19709 var html = target.innerHTML;
19711 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19715 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19717 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19723 picker : function()
19725 return this.pickerEl;
19728 fillMonths: function()
19731 var months = this.picker().select('>.datepicker-months td', true).first();
19733 months.dom.innerHTML = '';
19739 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19742 months.createChild(month);
19751 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19752 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19755 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19756 e.removeClass('active');
19758 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19759 e.addClass('active');
19766 if(this.isInline) {
19770 this.picker().removeClass(['bottom', 'top']);
19772 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19774 * place to the top of element!
19778 this.picker().addClass('top');
19779 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19784 this.picker().addClass('bottom');
19786 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19789 onFocus : function()
19791 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19795 onBlur : function()
19797 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19799 var d = this.inputEl().getValue();
19808 this.picker().show();
19809 this.picker().select('>.datepicker-months', true).first().show();
19813 this.fireEvent('show', this, this.date);
19818 if(this.isInline) {
19821 this.picker().hide();
19822 this.fireEvent('hide', this, this.date);
19826 onMousedown: function(e)
19828 e.stopPropagation();
19829 e.preventDefault();
19834 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19838 fireKey: function(e)
19840 if (!this.picker().isVisible()){
19841 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19852 e.preventDefault();
19856 dir = e.keyCode == 37 ? -1 : 1;
19858 this.vIndex = this.vIndex + dir;
19860 if(this.vIndex < 0){
19864 if(this.vIndex > 11){
19868 if(isNaN(this.vIndex)){
19872 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19878 dir = e.keyCode == 38 ? -1 : 1;
19880 this.vIndex = this.vIndex + dir * 4;
19882 if(this.vIndex < 0){
19886 if(this.vIndex > 11){
19890 if(isNaN(this.vIndex)){
19894 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19899 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19900 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19904 e.preventDefault();
19907 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19908 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19924 this.picker().remove();
19929 Roo.apply(Roo.bootstrap.MonthField, {
19948 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19949 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19954 Roo.apply(Roo.bootstrap.MonthField, {
19958 cls: 'datepicker dropdown-menu roo-dynamic',
19962 cls: 'datepicker-months',
19966 cls: 'table-condensed',
19968 Roo.bootstrap.DateField.content
19988 * @class Roo.bootstrap.CheckBox
19989 * @extends Roo.bootstrap.Input
19990 * Bootstrap CheckBox class
19992 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19993 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19994 * @cfg {String} boxLabel The text that appears beside the checkbox
19995 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19996 * @cfg {Boolean} checked initnal the element
19997 * @cfg {Boolean} inline inline the element (default false)
19998 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20001 * Create a new CheckBox
20002 * @param {Object} config The config object
20005 Roo.bootstrap.CheckBox = function(config){
20006 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20011 * Fires when the element is checked or unchecked.
20012 * @param {Roo.bootstrap.CheckBox} this This input
20013 * @param {Boolean} checked The new checked value
20020 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20022 inputType: 'checkbox',
20030 getAutoCreate : function()
20032 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20038 cfg.cls = 'form-group ' + this.inputType; //input-group
20041 cfg.cls += ' ' + this.inputType + '-inline';
20047 type : this.inputType,
20048 value : this.inputValue,
20049 cls : 'roo-' + this.inputType, //'form-box',
20050 placeholder : this.placeholder || ''
20054 if(this.inputType != 'radio'){
20058 cls : 'roo-hidden-value',
20059 value : this.checked ? this.valueOff : this.inputValue
20064 if (this.weight) { // Validity check?
20065 cfg.cls += " " + this.inputType + "-" + this.weight;
20068 if (this.disabled) {
20069 input.disabled=true;
20073 input.checked = this.checked;
20080 input.name = this.name;
20082 if(this.inputType != 'radio'){
20083 hidden.name = this.name;
20084 input.name = '_hidden_' + this.name;
20089 input.cls += ' input-' + this.size;
20094 ['xs','sm','md','lg'].map(function(size){
20095 if (settings[size]) {
20096 cfg.cls += ' col-' + size + '-' + settings[size];
20100 var inputblock = input;
20102 if (this.before || this.after) {
20105 cls : 'input-group',
20110 inputblock.cn.push({
20112 cls : 'input-group-addon',
20117 inputblock.cn.push(input);
20119 if(this.inputType != 'radio'){
20120 inputblock.cn.push(hidden);
20124 inputblock.cn.push({
20126 cls : 'input-group-addon',
20133 if (align ==='left' && this.fieldLabel.length) {
20134 // Roo.log("left and has label");
20139 cls : 'control-label',
20140 html : this.fieldLabel
20151 if(this.labelWidth > 12){
20152 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20155 if(this.labelWidth < 13 && this.labelmd == 0){
20156 this.labelmd = this.labelWidth;
20159 if(this.labellg > 0){
20160 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20161 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20164 if(this.labelmd > 0){
20165 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20166 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20169 if(this.labelsm > 0){
20170 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20171 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20174 if(this.labelxs > 0){
20175 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20176 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20179 } else if ( this.fieldLabel.length) {
20180 // Roo.log(" label");
20184 tag: this.boxLabel ? 'span' : 'label',
20186 cls: 'control-label box-input-label',
20187 //cls : 'input-group-addon',
20188 html : this.fieldLabel
20198 // Roo.log(" no label && no align");
20199 cfg.cn = [ inputblock ] ;
20205 var boxLabelCfg = {
20207 //'for': id, // box label is handled by onclick - so no for...
20209 html: this.boxLabel
20213 boxLabelCfg.tooltip = this.tooltip;
20216 cfg.cn.push(boxLabelCfg);
20219 if(this.inputType != 'radio'){
20220 cfg.cn.push(hidden);
20228 * return the real input element.
20230 inputEl: function ()
20232 return this.el.select('input.roo-' + this.inputType,true).first();
20234 hiddenEl: function ()
20236 return this.el.select('input.roo-hidden-value',true).first();
20239 labelEl: function()
20241 return this.el.select('label.control-label',true).first();
20243 /* depricated... */
20247 return this.labelEl();
20250 boxLabelEl: function()
20252 return this.el.select('label.box-label',true).first();
20255 initEvents : function()
20257 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20259 this.inputEl().on('click', this.onClick, this);
20261 if (this.boxLabel) {
20262 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20265 this.startValue = this.getValue();
20268 Roo.bootstrap.CheckBox.register(this);
20272 onClick : function()
20274 this.setChecked(!this.checked);
20277 setChecked : function(state,suppressEvent)
20279 this.startValue = this.getValue();
20281 if(this.inputType == 'radio'){
20283 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20284 e.dom.checked = false;
20287 this.inputEl().dom.checked = true;
20289 this.inputEl().dom.value = this.inputValue;
20291 if(suppressEvent !== true){
20292 this.fireEvent('check', this, true);
20300 this.checked = state;
20302 this.inputEl().dom.checked = state;
20305 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20307 if(suppressEvent !== true){
20308 this.fireEvent('check', this, state);
20314 getValue : function()
20316 if(this.inputType == 'radio'){
20317 return this.getGroupValue();
20320 return this.hiddenEl().dom.value;
20324 getGroupValue : function()
20326 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20330 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20333 setValue : function(v,suppressEvent)
20335 if(this.inputType == 'radio'){
20336 this.setGroupValue(v, suppressEvent);
20340 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20345 setGroupValue : function(v, suppressEvent)
20347 this.startValue = this.getValue();
20349 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20350 e.dom.checked = false;
20352 if(e.dom.value == v){
20353 e.dom.checked = true;
20357 if(suppressEvent !== true){
20358 this.fireEvent('check', this, true);
20366 validate : function()
20370 (this.inputType == 'radio' && this.validateRadio()) ||
20371 (this.inputType == 'checkbox' && this.validateCheckbox())
20377 this.markInvalid();
20381 validateRadio : function()
20383 if(this.allowBlank){
20389 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20390 if(!e.dom.checked){
20402 validateCheckbox : function()
20405 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20406 //return (this.getValue() == this.inputValue) ? true : false;
20409 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20417 for(var i in group){
20422 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20429 * Mark this field as valid
20431 markValid : function()
20435 this.fireEvent('valid', this);
20437 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20440 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20447 if(this.inputType == 'radio'){
20448 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20449 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20450 e.findParent('.form-group', false, true).addClass(_this.validClass);
20457 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20458 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20462 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20468 for(var i in group){
20469 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20470 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20475 * Mark this field as invalid
20476 * @param {String} msg The validation message
20478 markInvalid : function(msg)
20480 if(this.allowBlank){
20486 this.fireEvent('invalid', this, msg);
20488 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20491 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20495 label.markInvalid();
20498 if(this.inputType == 'radio'){
20499 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20500 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20501 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20508 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20509 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20513 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20519 for(var i in group){
20520 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20521 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20526 clearInvalid : function()
20528 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20530 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20532 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20535 label.iconEl.removeClass(label.validClass);
20536 label.iconEl.removeClass(label.invalidClass);
20540 disable : function()
20542 if(this.inputType != 'radio'){
20543 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20550 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20551 _this.getActionEl().addClass(this.disabledClass);
20552 e.dom.disabled = true;
20556 this.disabled = true;
20557 this.fireEvent("disable", this);
20561 enable : function()
20563 if(this.inputType != 'radio'){
20564 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20571 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20572 _this.getActionEl().removeClass(this.disabledClass);
20573 e.dom.disabled = false;
20577 this.disabled = false;
20578 this.fireEvent("enable", this);
20584 Roo.apply(Roo.bootstrap.CheckBox, {
20589 * register a CheckBox Group
20590 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20592 register : function(checkbox)
20594 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20595 this.groups[checkbox.groupId] = {};
20598 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20602 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20606 * fetch a CheckBox Group based on the group ID
20607 * @param {string} the group ID
20608 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20610 get: function(groupId) {
20611 if (typeof(this.groups[groupId]) == 'undefined') {
20615 return this.groups[groupId] ;
20628 * @class Roo.bootstrap.Radio
20629 * @extends Roo.bootstrap.Component
20630 * Bootstrap Radio class
20631 * @cfg {String} boxLabel - the label associated
20632 * @cfg {String} value - the value of radio
20635 * Create a new Radio
20636 * @param {Object} config The config object
20638 Roo.bootstrap.Radio = function(config){
20639 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20643 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20649 getAutoCreate : function()
20653 cls : 'form-group radio',
20658 html : this.boxLabel
20666 initEvents : function()
20668 this.parent().register(this);
20670 this.el.on('click', this.onClick, this);
20674 onClick : function()
20676 this.setChecked(true);
20679 setChecked : function(state, suppressEvent)
20681 this.parent().setValue(this.value, suppressEvent);
20696 * @class Roo.bootstrap.SecurePass
20697 * @extends Roo.bootstrap.Input
20698 * Bootstrap SecurePass class
20702 * Create a new SecurePass
20703 * @param {Object} config The config object
20706 Roo.bootstrap.SecurePass = function (config) {
20707 // these go here, so the translation tool can replace them..
20709 PwdEmpty: "Please type a password, and then retype it to confirm.",
20710 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20711 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20712 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20713 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20714 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20715 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20716 TooWeak: "Your password is Too Weak."
20718 this.meterLabel = "Password strength:";
20719 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20720 this.meterClass = ["roo-password-meter-tooweak",
20721 "roo-password-meter-weak",
20722 "roo-password-meter-medium",
20723 "roo-password-meter-strong",
20724 "roo-password-meter-grey"],
20725 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20728 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20730 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20732 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20733 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20734 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20735 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20736 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20737 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20738 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20748 * @cfg {String/Object} Label for the strength meter (defaults to
20749 * 'Password strength:')
20754 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20755 * ['Weak', 'Medium', 'Strong'])
20771 initEvents: function () {
20772 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20774 if (this.el.is('input[type=password]') && Roo.isSafari) {
20775 this.el.on('keydown', this.SafariOnKeyDown, this);
20778 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20781 onRender: function (ct, position) {
20782 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20783 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20784 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20786 this.trigger.createChild({
20791 cls: 'roo-password-meter-grey col-xs-12',
20794 //width: this.meterWidth + 'px'
20798 cls: 'roo-password-meter-text'
20804 this.trigger.createChild({
20806 cls: 'roo-password-meter-container col-xs-12',
20808 //width: this.meterWidth + 'px'
20812 cls: 'roo-password-meter-grey',
20814 //width: this.meterWidth + 'px'
20820 cls: 'roo-password-meter-grey col-xs-12',
20823 //width: this.meterWidth + 'px'
20827 cls: 'roo-password-meter-text'
20833 if (this.hideTrigger) {
20834 this.trigger.setDisplayed(false);
20836 this.setSize(this.width || '', this.height || '');
20839 onDestroy: function () {
20840 if (this.trigger) {
20841 this.trigger.removeAllListeners();
20842 this.trigger.remove();
20845 this.wrap.remove();
20847 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20850 checkStrength: function () {
20851 var pwd = this.inputEl().getValue();
20852 if (pwd == this._lastPwd) {
20857 if (this.ClientSideStrongPassword(pwd)) {
20859 } else if (this.ClientSideMediumPassword(pwd)) {
20861 } else if (this.ClientSideWeakPassword(pwd)) {
20867 console.log('strength1: ' + strength);
20869 //var pm = this.trigger.child('div/div/div').dom;
20870 var pm = this.trigger.child('div/div');
20871 pm.removeClass(this.meterClass);
20872 pm.addClass(this.meterClass[strength]);
20875 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20877 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20879 this._lastPwd = pwd;
20881 reset: function () {
20882 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20884 this._lastPwd = '';
20886 var pm = this.trigger.child('div/div');
20887 pm.removeClass(this.meterClass);
20888 pm.addClass('roo-password-meter-grey');
20891 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20894 this.inputEl().dom.type='password';
20897 validateValue: function (value) {
20899 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20902 if (value.length == 0) {
20903 if (this.allowBlank) {
20904 this.clearInvalid();
20908 this.markInvalid(this.errors.PwdEmpty);
20909 this.errorMsg = this.errors.PwdEmpty;
20917 if ('[\x21-\x7e]*'.match(value)) {
20918 this.markInvalid(this.errors.PwdBadChar);
20919 this.errorMsg = this.errors.PwdBadChar;
20922 if (value.length < 6) {
20923 this.markInvalid(this.errors.PwdShort);
20924 this.errorMsg = this.errors.PwdShort;
20927 if (value.length > 16) {
20928 this.markInvalid(this.errors.PwdLong);
20929 this.errorMsg = this.errors.PwdLong;
20933 if (this.ClientSideStrongPassword(value)) {
20935 } else if (this.ClientSideMediumPassword(value)) {
20937 } else if (this.ClientSideWeakPassword(value)) {
20944 if (strength < 2) {
20945 //this.markInvalid(this.errors.TooWeak);
20946 this.errorMsg = this.errors.TooWeak;
20951 console.log('strength2: ' + strength);
20953 //var pm = this.trigger.child('div/div/div').dom;
20955 var pm = this.trigger.child('div/div');
20956 pm.removeClass(this.meterClass);
20957 pm.addClass(this.meterClass[strength]);
20959 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20961 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20963 this.errorMsg = '';
20967 CharacterSetChecks: function (type) {
20969 this.fResult = false;
20972 isctype: function (character, type) {
20973 switch (type) { //why needed break after return in js ? very odd bug
20974 case this.kCapitalLetter:
20975 if (character >= 'A' && character <= 'Z') {
20979 case this.kSmallLetter:
20980 if (character >= 'a' && character <= 'z') {
20985 if (character >= '0' && character <= '9') {
20989 case this.kPunctuation:
20990 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21000 IsLongEnough: function (pwd, size) {
21001 return !(pwd == null || isNaN(size) || pwd.length < size);
21004 SpansEnoughCharacterSets: function (word, nb) {
21005 if (!this.IsLongEnough(word, nb))
21010 var characterSetChecks = new Array(
21011 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21012 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation));
21013 for (var index = 0; index < word.length; ++index) {
21014 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21015 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21016 characterSetChecks[nCharSet].fResult = true;
21023 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21024 if (characterSetChecks[nCharSet].fResult) {
21029 if (nCharSets < nb) {
21035 ClientSideStrongPassword: function (pwd) {
21036 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21039 ClientSideMediumPassword: function (pwd) {
21040 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21043 ClientSideWeakPassword: function (pwd) {
21044 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21047 })//<script type="text/javascript">
21050 * Based Ext JS Library 1.1.1
21051 * Copyright(c) 2006-2007, Ext JS, LLC.
21057 * @class Roo.HtmlEditorCore
21058 * @extends Roo.Component
21059 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21061 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21064 Roo.HtmlEditorCore = function(config){
21067 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21072 * @event initialize
21073 * Fires when the editor is fully initialized (including the iframe)
21074 * @param {Roo.HtmlEditorCore} this
21079 * Fires when the editor is first receives the focus. Any insertion must wait
21080 * until after this event.
21081 * @param {Roo.HtmlEditorCore} this
21085 * @event beforesync
21086 * Fires before the textarea is updated with content from the editor iframe. Return false
21087 * to cancel the sync.
21088 * @param {Roo.HtmlEditorCore} this
21089 * @param {String} html
21093 * @event beforepush
21094 * Fires before the iframe editor is updated with content from the textarea. Return false
21095 * to cancel the push.
21096 * @param {Roo.HtmlEditorCore} this
21097 * @param {String} html
21102 * Fires when the textarea is updated with content from the editor iframe.
21103 * @param {Roo.HtmlEditorCore} this
21104 * @param {String} html
21109 * Fires when the iframe editor is updated with content from the textarea.
21110 * @param {Roo.HtmlEditorCore} this
21111 * @param {String} html
21116 * @event editorevent
21117 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21118 * @param {Roo.HtmlEditorCore} this
21124 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21126 // defaults : white / black...
21127 this.applyBlacklists();
21134 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21138 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21144 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21149 * @cfg {Number} height (in pixels)
21153 * @cfg {Number} width (in pixels)
21158 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21161 stylesheets: false,
21166 // private properties
21167 validationEvent : false,
21169 initialized : false,
21171 sourceEditMode : false,
21172 onFocus : Roo.emptyFn,
21174 hideMode:'offsets',
21178 // blacklist + whitelisted elements..
21185 * Protected method that will not generally be called directly. It
21186 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21187 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21189 getDocMarkup : function(){
21193 // inherit styels from page...??
21194 if (this.stylesheets === false) {
21196 Roo.get(document.head).select('style').each(function(node) {
21197 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21200 Roo.get(document.head).select('link').each(function(node) {
21201 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21204 } else if (!this.stylesheets.length) {
21206 st = '<style type="text/css">' +
21207 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21213 st += '<style type="text/css">' +
21214 'IMG { cursor: pointer } ' +
21218 return '<html><head>' + st +
21219 //<style type="text/css">' +
21220 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21222 ' </head><body class="roo-htmleditor-body"></body></html>';
21226 onRender : function(ct, position)
21229 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21230 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21233 this.el.dom.style.border = '0 none';
21234 this.el.dom.setAttribute('tabIndex', -1);
21235 this.el.addClass('x-hidden hide');
21239 if(Roo.isIE){ // fix IE 1px bogus margin
21240 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21244 this.frameId = Roo.id();
21248 var iframe = this.owner.wrap.createChild({
21250 cls: 'form-control', // bootstrap..
21252 name: this.frameId,
21253 frameBorder : 'no',
21254 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21259 this.iframe = iframe.dom;
21261 this.assignDocWin();
21263 this.doc.designMode = 'on';
21266 this.doc.write(this.getDocMarkup());
21270 var task = { // must defer to wait for browser to be ready
21272 //console.log("run task?" + this.doc.readyState);
21273 this.assignDocWin();
21274 if(this.doc.body || this.doc.readyState == 'complete'){
21276 this.doc.designMode="on";
21280 Roo.TaskMgr.stop(task);
21281 this.initEditor.defer(10, this);
21288 Roo.TaskMgr.start(task);
21293 onResize : function(w, h)
21295 Roo.log('resize: ' +w + ',' + h );
21296 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21300 if(typeof w == 'number'){
21302 this.iframe.style.width = w + 'px';
21304 if(typeof h == 'number'){
21306 this.iframe.style.height = h + 'px';
21308 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21315 * Toggles the editor between standard and source edit mode.
21316 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21318 toggleSourceEdit : function(sourceEditMode){
21320 this.sourceEditMode = sourceEditMode === true;
21322 if(this.sourceEditMode){
21324 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21327 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21328 //this.iframe.className = '';
21331 //this.setSize(this.owner.wrap.getSize());
21332 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21339 * Protected method that will not generally be called directly. If you need/want
21340 * custom HTML cleanup, this is the method you should override.
21341 * @param {String} html The HTML to be cleaned
21342 * return {String} The cleaned HTML
21344 cleanHtml : function(html){
21345 html = String(html);
21346 if(html.length > 5){
21347 if(Roo.isSafari){ // strip safari nonsense
21348 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21351 if(html == ' '){
21358 * HTML Editor -> Textarea
21359 * Protected method that will not generally be called directly. Syncs the contents
21360 * of the editor iframe with the textarea.
21362 syncValue : function(){
21363 if(this.initialized){
21364 var bd = (this.doc.body || this.doc.documentElement);
21365 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21366 var html = bd.innerHTML;
21368 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21369 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21371 html = '<div style="'+m[0]+'">' + html + '</div>';
21374 html = this.cleanHtml(html);
21375 // fix up the special chars.. normaly like back quotes in word...
21376 // however we do not want to do this with chinese..
21377 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21378 var cc = b.charCodeAt();
21380 (cc >= 0x4E00 && cc < 0xA000 ) ||
21381 (cc >= 0x3400 && cc < 0x4E00 ) ||
21382 (cc >= 0xf900 && cc < 0xfb00 )
21388 if(this.owner.fireEvent('beforesync', this, html) !== false){
21389 this.el.dom.value = html;
21390 this.owner.fireEvent('sync', this, html);
21396 * Protected method that will not generally be called directly. Pushes the value of the textarea
21397 * into the iframe editor.
21399 pushValue : function(){
21400 if(this.initialized){
21401 var v = this.el.dom.value.trim();
21403 // if(v.length < 1){
21407 if(this.owner.fireEvent('beforepush', this, v) !== false){
21408 var d = (this.doc.body || this.doc.documentElement);
21410 this.cleanUpPaste();
21411 this.el.dom.value = d.innerHTML;
21412 this.owner.fireEvent('push', this, v);
21418 deferFocus : function(){
21419 this.focus.defer(10, this);
21423 focus : function(){
21424 if(this.win && !this.sourceEditMode){
21431 assignDocWin: function()
21433 var iframe = this.iframe;
21436 this.doc = iframe.contentWindow.document;
21437 this.win = iframe.contentWindow;
21439 // if (!Roo.get(this.frameId)) {
21442 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21443 // this.win = Roo.get(this.frameId).dom.contentWindow;
21445 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21449 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21450 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21455 initEditor : function(){
21456 //console.log("INIT EDITOR");
21457 this.assignDocWin();
21461 this.doc.designMode="on";
21463 this.doc.write(this.getDocMarkup());
21466 var dbody = (this.doc.body || this.doc.documentElement);
21467 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21468 // this copies styles from the containing element into thsi one..
21469 // not sure why we need all of this..
21470 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21472 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21473 //ss['background-attachment'] = 'fixed'; // w3c
21474 dbody.bgProperties = 'fixed'; // ie
21475 //Roo.DomHelper.applyStyles(dbody, ss);
21476 Roo.EventManager.on(this.doc, {
21477 //'mousedown': this.onEditorEvent,
21478 'mouseup': this.onEditorEvent,
21479 'dblclick': this.onEditorEvent,
21480 'click': this.onEditorEvent,
21481 'keyup': this.onEditorEvent,
21486 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21488 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21489 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21491 this.initialized = true;
21493 this.owner.fireEvent('initialize', this);
21498 onDestroy : function(){
21504 //for (var i =0; i < this.toolbars.length;i++) {
21505 // // fixme - ask toolbars for heights?
21506 // this.toolbars[i].onDestroy();
21509 //this.wrap.dom.innerHTML = '';
21510 //this.wrap.remove();
21515 onFirstFocus : function(){
21517 this.assignDocWin();
21520 this.activated = true;
21523 if(Roo.isGecko){ // prevent silly gecko errors
21525 var s = this.win.getSelection();
21526 if(!s.focusNode || s.focusNode.nodeType != 3){
21527 var r = s.getRangeAt(0);
21528 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21533 this.execCmd('useCSS', true);
21534 this.execCmd('styleWithCSS', false);
21537 this.owner.fireEvent('activate', this);
21541 adjustFont: function(btn){
21542 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21543 //if(Roo.isSafari){ // safari
21546 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21547 if(Roo.isSafari){ // safari
21548 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21549 v = (v < 10) ? 10 : v;
21550 v = (v > 48) ? 48 : v;
21551 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21556 v = Math.max(1, v+adjust);
21558 this.execCmd('FontSize', v );
21561 onEditorEvent : function(e)
21563 this.owner.fireEvent('editorevent', this, e);
21564 // this.updateToolbar();
21565 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21568 insertTag : function(tg)
21570 // could be a bit smarter... -> wrap the current selected tRoo..
21571 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21573 range = this.createRange(this.getSelection());
21574 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21575 wrappingNode.appendChild(range.extractContents());
21576 range.insertNode(wrappingNode);
21583 this.execCmd("formatblock", tg);
21587 insertText : function(txt)
21591 var range = this.createRange();
21592 range.deleteContents();
21593 //alert(Sender.getAttribute('label'));
21595 range.insertNode(this.doc.createTextNode(txt));
21601 * Executes a Midas editor command on the editor document and performs necessary focus and
21602 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21603 * @param {String} cmd The Midas command
21604 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21606 relayCmd : function(cmd, value){
21608 this.execCmd(cmd, value);
21609 this.owner.fireEvent('editorevent', this);
21610 //this.updateToolbar();
21611 this.owner.deferFocus();
21615 * Executes a Midas editor command directly on the editor document.
21616 * For visual commands, you should use {@link #relayCmd} instead.
21617 * <b>This should only be called after the editor is initialized.</b>
21618 * @param {String} cmd The Midas command
21619 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21621 execCmd : function(cmd, value){
21622 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21629 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21631 * @param {String} text | dom node..
21633 insertAtCursor : function(text)
21638 if(!this.activated){
21644 var r = this.doc.selection.createRange();
21655 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21659 // from jquery ui (MIT licenced)
21661 var win = this.win;
21663 if (win.getSelection && win.getSelection().getRangeAt) {
21664 range = win.getSelection().getRangeAt(0);
21665 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21666 range.insertNode(node);
21667 } else if (win.document.selection && win.document.selection.createRange) {
21668 // no firefox support
21669 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21670 win.document.selection.createRange().pasteHTML(txt);
21672 // no firefox support
21673 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21674 this.execCmd('InsertHTML', txt);
21683 mozKeyPress : function(e){
21685 var c = e.getCharCode(), cmd;
21688 c = String.fromCharCode(c).toLowerCase();
21702 this.cleanUpPaste.defer(100, this);
21710 e.preventDefault();
21718 fixKeys : function(){ // load time branching for fastest keydown performance
21720 return function(e){
21721 var k = e.getKey(), r;
21724 r = this.doc.selection.createRange();
21727 r.pasteHTML('    ');
21734 r = this.doc.selection.createRange();
21736 var target = r.parentElement();
21737 if(!target || target.tagName.toLowerCase() != 'li'){
21739 r.pasteHTML('<br />');
21745 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21746 this.cleanUpPaste.defer(100, this);
21752 }else if(Roo.isOpera){
21753 return function(e){
21754 var k = e.getKey();
21758 this.execCmd('InsertHTML','    ');
21761 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21762 this.cleanUpPaste.defer(100, this);
21767 }else if(Roo.isSafari){
21768 return function(e){
21769 var k = e.getKey();
21773 this.execCmd('InsertText','\t');
21777 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21778 this.cleanUpPaste.defer(100, this);
21786 getAllAncestors: function()
21788 var p = this.getSelectedNode();
21791 a.push(p); // push blank onto stack..
21792 p = this.getParentElement();
21796 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21800 a.push(this.doc.body);
21804 lastSelNode : false,
21807 getSelection : function()
21809 this.assignDocWin();
21810 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21813 getSelectedNode: function()
21815 // this may only work on Gecko!!!
21817 // should we cache this!!!!
21822 var range = this.createRange(this.getSelection()).cloneRange();
21825 var parent = range.parentElement();
21827 var testRange = range.duplicate();
21828 testRange.moveToElementText(parent);
21829 if (testRange.inRange(range)) {
21832 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21835 parent = parent.parentElement;
21840 // is ancestor a text element.
21841 var ac = range.commonAncestorContainer;
21842 if (ac.nodeType == 3) {
21843 ac = ac.parentNode;
21846 var ar = ac.childNodes;
21849 var other_nodes = [];
21850 var has_other_nodes = false;
21851 for (var i=0;i<ar.length;i++) {
21852 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21855 // fullly contained node.
21857 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21862 // probably selected..
21863 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21864 other_nodes.push(ar[i]);
21868 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21873 has_other_nodes = true;
21875 if (!nodes.length && other_nodes.length) {
21876 nodes= other_nodes;
21878 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21884 createRange: function(sel)
21886 // this has strange effects when using with
21887 // top toolbar - not sure if it's a great idea.
21888 //this.editor.contentWindow.focus();
21889 if (typeof sel != "undefined") {
21891 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21893 return this.doc.createRange();
21896 return this.doc.createRange();
21899 getParentElement: function()
21902 this.assignDocWin();
21903 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21905 var range = this.createRange(sel);
21908 var p = range.commonAncestorContainer;
21909 while (p.nodeType == 3) { // text node
21920 * Range intersection.. the hard stuff...
21924 * [ -- selected range --- ]
21928 * if end is before start or hits it. fail.
21929 * if start is after end or hits it fail.
21931 * if either hits (but other is outside. - then it's not
21937 // @see http://www.thismuchiknow.co.uk/?p=64.
21938 rangeIntersectsNode : function(range, node)
21940 var nodeRange = node.ownerDocument.createRange();
21942 nodeRange.selectNode(node);
21944 nodeRange.selectNodeContents(node);
21947 var rangeStartRange = range.cloneRange();
21948 rangeStartRange.collapse(true);
21950 var rangeEndRange = range.cloneRange();
21951 rangeEndRange.collapse(false);
21953 var nodeStartRange = nodeRange.cloneRange();
21954 nodeStartRange.collapse(true);
21956 var nodeEndRange = nodeRange.cloneRange();
21957 nodeEndRange.collapse(false);
21959 return rangeStartRange.compareBoundaryPoints(
21960 Range.START_TO_START, nodeEndRange) == -1 &&
21961 rangeEndRange.compareBoundaryPoints(
21962 Range.START_TO_START, nodeStartRange) == 1;
21966 rangeCompareNode : function(range, node)
21968 var nodeRange = node.ownerDocument.createRange();
21970 nodeRange.selectNode(node);
21972 nodeRange.selectNodeContents(node);
21976 range.collapse(true);
21978 nodeRange.collapse(true);
21980 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21981 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21983 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21985 var nodeIsBefore = ss == 1;
21986 var nodeIsAfter = ee == -1;
21988 if (nodeIsBefore && nodeIsAfter) {
21991 if (!nodeIsBefore && nodeIsAfter) {
21992 return 1; //right trailed.
21995 if (nodeIsBefore && !nodeIsAfter) {
21996 return 2; // left trailed.
22002 // private? - in a new class?
22003 cleanUpPaste : function()
22005 // cleans up the whole document..
22006 Roo.log('cleanuppaste');
22008 this.cleanUpChildren(this.doc.body);
22009 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22010 if (clean != this.doc.body.innerHTML) {
22011 this.doc.body.innerHTML = clean;
22016 cleanWordChars : function(input) {// change the chars to hex code
22017 var he = Roo.HtmlEditorCore;
22019 var output = input;
22020 Roo.each(he.swapCodes, function(sw) {
22021 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22023 output = output.replace(swapper, sw[1]);
22030 cleanUpChildren : function (n)
22032 if (!n.childNodes.length) {
22035 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22036 this.cleanUpChild(n.childNodes[i]);
22043 cleanUpChild : function (node)
22046 //console.log(node);
22047 if (node.nodeName == "#text") {
22048 // clean up silly Windows -- stuff?
22051 if (node.nodeName == "#comment") {
22052 node.parentNode.removeChild(node);
22053 // clean up silly Windows -- stuff?
22056 var lcname = node.tagName.toLowerCase();
22057 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22058 // whitelist of tags..
22060 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22062 node.parentNode.removeChild(node);
22067 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22069 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22070 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22072 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22073 // remove_keep_children = true;
22076 if (remove_keep_children) {
22077 this.cleanUpChildren(node);
22078 // inserts everything just before this node...
22079 while (node.childNodes.length) {
22080 var cn = node.childNodes[0];
22081 node.removeChild(cn);
22082 node.parentNode.insertBefore(cn, node);
22084 node.parentNode.removeChild(node);
22088 if (!node.attributes || !node.attributes.length) {
22089 this.cleanUpChildren(node);
22093 function cleanAttr(n,v)
22096 if (v.match(/^\./) || v.match(/^\//)) {
22099 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22102 if (v.match(/^#/)) {
22105 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22106 node.removeAttribute(n);
22110 var cwhite = this.cwhite;
22111 var cblack = this.cblack;
22113 function cleanStyle(n,v)
22115 if (v.match(/expression/)) { //XSS?? should we even bother..
22116 node.removeAttribute(n);
22120 var parts = v.split(/;/);
22123 Roo.each(parts, function(p) {
22124 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22128 var l = p.split(':').shift().replace(/\s+/g,'');
22129 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22131 if ( cwhite.length && cblack.indexOf(l) > -1) {
22132 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22133 //node.removeAttribute(n);
22137 // only allow 'c whitelisted system attributes'
22138 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22139 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22140 //node.removeAttribute(n);
22150 if (clean.length) {
22151 node.setAttribute(n, clean.join(';'));
22153 node.removeAttribute(n);
22159 for (var i = node.attributes.length-1; i > -1 ; i--) {
22160 var a = node.attributes[i];
22163 if (a.name.toLowerCase().substr(0,2)=='on') {
22164 node.removeAttribute(a.name);
22167 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22168 node.removeAttribute(a.name);
22171 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22172 cleanAttr(a.name,a.value); // fixme..
22175 if (a.name == 'style') {
22176 cleanStyle(a.name,a.value);
22179 /// clean up MS crap..
22180 // tecnically this should be a list of valid class'es..
22183 if (a.name == 'class') {
22184 if (a.value.match(/^Mso/)) {
22185 node.className = '';
22188 if (a.value.match(/body/)) {
22189 node.className = '';
22200 this.cleanUpChildren(node);
22206 * Clean up MS wordisms...
22208 cleanWord : function(node)
22213 this.cleanWord(this.doc.body);
22216 if (node.nodeName == "#text") {
22217 // clean up silly Windows -- stuff?
22220 if (node.nodeName == "#comment") {
22221 node.parentNode.removeChild(node);
22222 // clean up silly Windows -- stuff?
22226 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22227 node.parentNode.removeChild(node);
22231 // remove - but keep children..
22232 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22233 while (node.childNodes.length) {
22234 var cn = node.childNodes[0];
22235 node.removeChild(cn);
22236 node.parentNode.insertBefore(cn, node);
22238 node.parentNode.removeChild(node);
22239 this.iterateChildren(node, this.cleanWord);
22243 if (node.className.length) {
22245 var cn = node.className.split(/\W+/);
22247 Roo.each(cn, function(cls) {
22248 if (cls.match(/Mso[a-zA-Z]+/)) {
22253 node.className = cna.length ? cna.join(' ') : '';
22255 node.removeAttribute("class");
22259 if (node.hasAttribute("lang")) {
22260 node.removeAttribute("lang");
22263 if (node.hasAttribute("style")) {
22265 var styles = node.getAttribute("style").split(";");
22267 Roo.each(styles, function(s) {
22268 if (!s.match(/:/)) {
22271 var kv = s.split(":");
22272 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22275 // what ever is left... we allow.
22278 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22279 if (!nstyle.length) {
22280 node.removeAttribute('style');
22283 this.iterateChildren(node, this.cleanWord);
22289 * iterateChildren of a Node, calling fn each time, using this as the scole..
22290 * @param {DomNode} node node to iterate children of.
22291 * @param {Function} fn method of this class to call on each item.
22293 iterateChildren : function(node, fn)
22295 if (!node.childNodes.length) {
22298 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22299 fn.call(this, node.childNodes[i])
22305 * cleanTableWidths.
22307 * Quite often pasting from word etc.. results in tables with column and widths.
22308 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22311 cleanTableWidths : function(node)
22316 this.cleanTableWidths(this.doc.body);
22321 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22324 Roo.log(node.tagName);
22325 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22326 this.iterateChildren(node, this.cleanTableWidths);
22329 if (node.hasAttribute('width')) {
22330 node.removeAttribute('width');
22334 if (node.hasAttribute("style")) {
22337 var styles = node.getAttribute("style").split(";");
22339 Roo.each(styles, function(s) {
22340 if (!s.match(/:/)) {
22343 var kv = s.split(":");
22344 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22347 // what ever is left... we allow.
22350 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22351 if (!nstyle.length) {
22352 node.removeAttribute('style');
22356 this.iterateChildren(node, this.cleanTableWidths);
22364 domToHTML : function(currentElement, depth, nopadtext) {
22366 depth = depth || 0;
22367 nopadtext = nopadtext || false;
22369 if (!currentElement) {
22370 return this.domToHTML(this.doc.body);
22373 //Roo.log(currentElement);
22375 var allText = false;
22376 var nodeName = currentElement.nodeName;
22377 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22379 if (nodeName == '#text') {
22381 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22386 if (nodeName != 'BODY') {
22389 // Prints the node tagName, such as <A>, <IMG>, etc
22392 for(i = 0; i < currentElement.attributes.length;i++) {
22394 var aname = currentElement.attributes.item(i).name;
22395 if (!currentElement.attributes.item(i).value.length) {
22398 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22401 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22410 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22413 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22418 // Traverse the tree
22420 var currentElementChild = currentElement.childNodes.item(i);
22421 var allText = true;
22422 var innerHTML = '';
22424 while (currentElementChild) {
22425 // Formatting code (indent the tree so it looks nice on the screen)
22426 var nopad = nopadtext;
22427 if (lastnode == 'SPAN') {
22431 if (currentElementChild.nodeName == '#text') {
22432 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22433 toadd = nopadtext ? toadd : toadd.trim();
22434 if (!nopad && toadd.length > 80) {
22435 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22437 innerHTML += toadd;
22440 currentElementChild = currentElement.childNodes.item(i);
22446 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22448 // Recursively traverse the tree structure of the child node
22449 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22450 lastnode = currentElementChild.nodeName;
22452 currentElementChild=currentElement.childNodes.item(i);
22458 // The remaining code is mostly for formatting the tree
22459 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22464 ret+= "</"+tagName+">";
22470 applyBlacklists : function()
22472 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22473 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22477 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22478 if (b.indexOf(tag) > -1) {
22481 this.white.push(tag);
22485 Roo.each(w, function(tag) {
22486 if (b.indexOf(tag) > -1) {
22489 if (this.white.indexOf(tag) > -1) {
22492 this.white.push(tag);
22497 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22498 if (w.indexOf(tag) > -1) {
22501 this.black.push(tag);
22505 Roo.each(b, function(tag) {
22506 if (w.indexOf(tag) > -1) {
22509 if (this.black.indexOf(tag) > -1) {
22512 this.black.push(tag);
22517 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22518 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22522 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22523 if (b.indexOf(tag) > -1) {
22526 this.cwhite.push(tag);
22530 Roo.each(w, function(tag) {
22531 if (b.indexOf(tag) > -1) {
22534 if (this.cwhite.indexOf(tag) > -1) {
22537 this.cwhite.push(tag);
22542 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22543 if (w.indexOf(tag) > -1) {
22546 this.cblack.push(tag);
22550 Roo.each(b, function(tag) {
22551 if (w.indexOf(tag) > -1) {
22554 if (this.cblack.indexOf(tag) > -1) {
22557 this.cblack.push(tag);
22562 setStylesheets : function(stylesheets)
22564 if(typeof(stylesheets) == 'string'){
22565 Roo.get(this.iframe.contentDocument.head).createChild({
22567 rel : 'stylesheet',
22576 Roo.each(stylesheets, function(s) {
22581 Roo.get(_this.iframe.contentDocument.head).createChild({
22583 rel : 'stylesheet',
22592 removeStylesheets : function()
22596 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22601 // hide stuff that is not compatible
22615 * @event specialkey
22619 * @cfg {String} fieldClass @hide
22622 * @cfg {String} focusClass @hide
22625 * @cfg {String} autoCreate @hide
22628 * @cfg {String} inputType @hide
22631 * @cfg {String} invalidClass @hide
22634 * @cfg {String} invalidText @hide
22637 * @cfg {String} msgFx @hide
22640 * @cfg {String} validateOnBlur @hide
22644 Roo.HtmlEditorCore.white = [
22645 'area', 'br', 'img', 'input', 'hr', 'wbr',
22647 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22648 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22649 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22650 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22651 'table', 'ul', 'xmp',
22653 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22656 'dir', 'menu', 'ol', 'ul', 'dl',
22662 Roo.HtmlEditorCore.black = [
22663 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22665 'base', 'basefont', 'bgsound', 'blink', 'body',
22666 'frame', 'frameset', 'head', 'html', 'ilayer',
22667 'iframe', 'layer', 'link', 'meta', 'object',
22668 'script', 'style' ,'title', 'xml' // clean later..
22670 Roo.HtmlEditorCore.clean = [
22671 'script', 'style', 'title', 'xml'
22673 Roo.HtmlEditorCore.remove = [
22678 Roo.HtmlEditorCore.ablack = [
22682 Roo.HtmlEditorCore.aclean = [
22683 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22687 Roo.HtmlEditorCore.pwhite= [
22688 'http', 'https', 'mailto'
22691 // white listed style attributes.
22692 Roo.HtmlEditorCore.cwhite= [
22693 // 'text-align', /// default is to allow most things..
22699 // black listed style attributes.
22700 Roo.HtmlEditorCore.cblack= [
22701 // 'font-size' -- this can be set by the project
22705 Roo.HtmlEditorCore.swapCodes =[
22724 * @class Roo.bootstrap.HtmlEditor
22725 * @extends Roo.bootstrap.TextArea
22726 * Bootstrap HtmlEditor class
22729 * Create a new HtmlEditor
22730 * @param {Object} config The config object
22733 Roo.bootstrap.HtmlEditor = function(config){
22734 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22735 if (!this.toolbars) {
22736 this.toolbars = [];
22738 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22741 * @event initialize
22742 * Fires when the editor is fully initialized (including the iframe)
22743 * @param {HtmlEditor} this
22748 * Fires when the editor is first receives the focus. Any insertion must wait
22749 * until after this event.
22750 * @param {HtmlEditor} this
22754 * @event beforesync
22755 * Fires before the textarea is updated with content from the editor iframe. Return false
22756 * to cancel the sync.
22757 * @param {HtmlEditor} this
22758 * @param {String} html
22762 * @event beforepush
22763 * Fires before the iframe editor is updated with content from the textarea. Return false
22764 * to cancel the push.
22765 * @param {HtmlEditor} this
22766 * @param {String} html
22771 * Fires when the textarea is updated with content from the editor iframe.
22772 * @param {HtmlEditor} this
22773 * @param {String} html
22778 * Fires when the iframe editor is updated with content from the textarea.
22779 * @param {HtmlEditor} this
22780 * @param {String} html
22784 * @event editmodechange
22785 * Fires when the editor switches edit modes
22786 * @param {HtmlEditor} this
22787 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22789 editmodechange: true,
22791 * @event editorevent
22792 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22793 * @param {HtmlEditor} this
22797 * @event firstfocus
22798 * Fires when on first focus - needed by toolbars..
22799 * @param {HtmlEditor} this
22804 * Auto save the htmlEditor value as a file into Events
22805 * @param {HtmlEditor} this
22809 * @event savedpreview
22810 * preview the saved version of htmlEditor
22811 * @param {HtmlEditor} this
22818 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22822 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22827 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22832 * @cfg {Number} height (in pixels)
22836 * @cfg {Number} width (in pixels)
22841 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22844 stylesheets: false,
22849 // private properties
22850 validationEvent : false,
22852 initialized : false,
22855 onFocus : Roo.emptyFn,
22857 hideMode:'offsets',
22860 tbContainer : false,
22862 toolbarContainer :function() {
22863 return this.wrap.select('.x-html-editor-tb',true).first();
22867 * Protected method that will not generally be called directly. It
22868 * is called when the editor creates its toolbar. Override this method if you need to
22869 * add custom toolbar buttons.
22870 * @param {HtmlEditor} editor
22872 createToolbar : function(){
22874 Roo.log("create toolbars");
22876 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22877 this.toolbars[0].render(this.toolbarContainer());
22881 // if (!editor.toolbars || !editor.toolbars.length) {
22882 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22885 // for (var i =0 ; i < editor.toolbars.length;i++) {
22886 // editor.toolbars[i] = Roo.factory(
22887 // typeof(editor.toolbars[i]) == 'string' ?
22888 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22889 // Roo.bootstrap.HtmlEditor);
22890 // editor.toolbars[i].init(editor);
22896 onRender : function(ct, position)
22898 // Roo.log("Call onRender: " + this.xtype);
22900 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22902 this.wrap = this.inputEl().wrap({
22903 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22906 this.editorcore.onRender(ct, position);
22908 if (this.resizable) {
22909 this.resizeEl = new Roo.Resizable(this.wrap, {
22913 minHeight : this.height,
22914 height: this.height,
22915 handles : this.resizable,
22918 resize : function(r, w, h) {
22919 _t.onResize(w,h); // -something
22925 this.createToolbar(this);
22928 if(!this.width && this.resizable){
22929 this.setSize(this.wrap.getSize());
22931 if (this.resizeEl) {
22932 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22933 // should trigger onReize..
22939 onResize : function(w, h)
22941 Roo.log('resize: ' +w + ',' + h );
22942 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22946 if(this.inputEl() ){
22947 if(typeof w == 'number'){
22948 var aw = w - this.wrap.getFrameWidth('lr');
22949 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22952 if(typeof h == 'number'){
22953 var tbh = -11; // fixme it needs to tool bar size!
22954 for (var i =0; i < this.toolbars.length;i++) {
22955 // fixme - ask toolbars for heights?
22956 tbh += this.toolbars[i].el.getHeight();
22957 //if (this.toolbars[i].footer) {
22958 // tbh += this.toolbars[i].footer.el.getHeight();
22966 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22967 ah -= 5; // knock a few pixes off for look..
22968 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22972 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22973 this.editorcore.onResize(ew,eh);
22978 * Toggles the editor between standard and source edit mode.
22979 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22981 toggleSourceEdit : function(sourceEditMode)
22983 this.editorcore.toggleSourceEdit(sourceEditMode);
22985 if(this.editorcore.sourceEditMode){
22986 Roo.log('editor - showing textarea');
22989 // Roo.log(this.syncValue());
22991 this.inputEl().removeClass(['hide', 'x-hidden']);
22992 this.inputEl().dom.removeAttribute('tabIndex');
22993 this.inputEl().focus();
22995 Roo.log('editor - hiding textarea');
22997 // Roo.log(this.pushValue());
23000 this.inputEl().addClass(['hide', 'x-hidden']);
23001 this.inputEl().dom.setAttribute('tabIndex', -1);
23002 //this.deferFocus();
23005 if(this.resizable){
23006 this.setSize(this.wrap.getSize());
23009 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23012 // private (for BoxComponent)
23013 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23015 // private (for BoxComponent)
23016 getResizeEl : function(){
23020 // private (for BoxComponent)
23021 getPositionEl : function(){
23026 initEvents : function(){
23027 this.originalValue = this.getValue();
23031 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23034 // markInvalid : Roo.emptyFn,
23036 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23039 // clearInvalid : Roo.emptyFn,
23041 setValue : function(v){
23042 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23043 this.editorcore.pushValue();
23048 deferFocus : function(){
23049 this.focus.defer(10, this);
23053 focus : function(){
23054 this.editorcore.focus();
23060 onDestroy : function(){
23066 for (var i =0; i < this.toolbars.length;i++) {
23067 // fixme - ask toolbars for heights?
23068 this.toolbars[i].onDestroy();
23071 this.wrap.dom.innerHTML = '';
23072 this.wrap.remove();
23077 onFirstFocus : function(){
23078 //Roo.log("onFirstFocus");
23079 this.editorcore.onFirstFocus();
23080 for (var i =0; i < this.toolbars.length;i++) {
23081 this.toolbars[i].onFirstFocus();
23087 syncValue : function()
23089 this.editorcore.syncValue();
23092 pushValue : function()
23094 this.editorcore.pushValue();
23098 // hide stuff that is not compatible
23112 * @event specialkey
23116 * @cfg {String} fieldClass @hide
23119 * @cfg {String} focusClass @hide
23122 * @cfg {String} autoCreate @hide
23125 * @cfg {String} inputType @hide
23128 * @cfg {String} invalidClass @hide
23131 * @cfg {String} invalidText @hide
23134 * @cfg {String} msgFx @hide
23137 * @cfg {String} validateOnBlur @hide
23146 Roo.namespace('Roo.bootstrap.htmleditor');
23148 * @class Roo.bootstrap.HtmlEditorToolbar1
23153 new Roo.bootstrap.HtmlEditor({
23156 new Roo.bootstrap.HtmlEditorToolbar1({
23157 disable : { fonts: 1 , format: 1, ..., ... , ...],
23163 * @cfg {Object} disable List of elements to disable..
23164 * @cfg {Array} btns List of additional buttons.
23168 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23171 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23174 Roo.apply(this, config);
23176 // default disabled, based on 'good practice'..
23177 this.disable = this.disable || {};
23178 Roo.applyIf(this.disable, {
23181 specialElements : true
23183 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23185 this.editor = config.editor;
23186 this.editorcore = config.editor.editorcore;
23188 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23190 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23191 // dont call parent... till later.
23193 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23198 editorcore : false,
23203 "h1","h2","h3","h4","h5","h6",
23205 "abbr", "acronym", "address", "cite", "samp", "var",
23209 onRender : function(ct, position)
23211 // Roo.log("Call onRender: " + this.xtype);
23213 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23215 this.el.dom.style.marginBottom = '0';
23217 var editorcore = this.editorcore;
23218 var editor= this.editor;
23221 var btn = function(id,cmd , toggle, handler){
23223 var event = toggle ? 'toggle' : 'click';
23228 xns: Roo.bootstrap,
23231 enableToggle:toggle !== false,
23233 pressed : toggle ? false : null,
23236 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23237 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23246 xns: Roo.bootstrap,
23247 glyphicon : 'font',
23251 xns: Roo.bootstrap,
23255 Roo.each(this.formats, function(f) {
23256 style.menu.items.push({
23258 xns: Roo.bootstrap,
23259 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23264 editorcore.insertTag(this.tagname);
23271 children.push(style);
23274 btn('bold',false,true);
23275 btn('italic',false,true);
23276 btn('align-left', 'justifyleft',true);
23277 btn('align-center', 'justifycenter',true);
23278 btn('align-right' , 'justifyright',true);
23279 btn('link', false, false, function(btn) {
23280 //Roo.log("create link?");
23281 var url = prompt(this.createLinkText, this.defaultLinkValue);
23282 if(url && url != 'http:/'+'/'){
23283 this.editorcore.relayCmd('createlink', url);
23286 btn('list','insertunorderedlist',true);
23287 btn('pencil', false,true, function(btn){
23290 this.toggleSourceEdit(btn.pressed);
23296 xns: Roo.bootstrap,
23301 xns: Roo.bootstrap,
23306 cog.menu.items.push({
23308 xns: Roo.bootstrap,
23309 html : Clean styles,
23314 editorcore.insertTag(this.tagname);
23323 this.xtype = 'NavSimplebar';
23325 for(var i=0;i< children.length;i++) {
23327 this.buttons.add(this.addxtypeChild(children[i]));
23331 editor.on('editorevent', this.updateToolbar, this);
23333 onBtnClick : function(id)
23335 this.editorcore.relayCmd(id);
23336 this.editorcore.focus();
23340 * Protected method that will not generally be called directly. It triggers
23341 * a toolbar update by reading the markup state of the current selection in the editor.
23343 updateToolbar: function(){
23345 if(!this.editorcore.activated){
23346 this.editor.onFirstFocus(); // is this neeed?
23350 var btns = this.buttons;
23351 var doc = this.editorcore.doc;
23352 btns.get('bold').setActive(doc.queryCommandState('bold'));
23353 btns.get('italic').setActive(doc.queryCommandState('italic'));
23354 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23356 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23357 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23358 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23360 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23361 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23364 var ans = this.editorcore.getAllAncestors();
23365 if (this.formatCombo) {
23368 var store = this.formatCombo.store;
23369 this.formatCombo.setValue("");
23370 for (var i =0; i < ans.length;i++) {
23371 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23373 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23381 // hides menus... - so this cant be on a menu...
23382 Roo.bootstrap.MenuMgr.hideAll();
23384 Roo.bootstrap.MenuMgr.hideAll();
23385 //this.editorsyncValue();
23387 onFirstFocus: function() {
23388 this.buttons.each(function(item){
23392 toggleSourceEdit : function(sourceEditMode){
23395 if(sourceEditMode){
23396 Roo.log("disabling buttons");
23397 this.buttons.each( function(item){
23398 if(item.cmd != 'pencil'){
23404 Roo.log("enabling buttons");
23405 if(this.editorcore.initialized){
23406 this.buttons.each( function(item){
23412 Roo.log("calling toggole on editor");
23413 // tell the editor that it's been pressed..
23414 this.editor.toggleSourceEdit(sourceEditMode);
23424 * @class Roo.bootstrap.Table.AbstractSelectionModel
23425 * @extends Roo.util.Observable
23426 * Abstract base class for grid SelectionModels. It provides the interface that should be
23427 * implemented by descendant classes. This class should not be directly instantiated.
23430 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23431 this.locked = false;
23432 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23436 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23437 /** @ignore Called by the grid automatically. Do not call directly. */
23438 init : function(grid){
23444 * Locks the selections.
23447 this.locked = true;
23451 * Unlocks the selections.
23453 unlock : function(){
23454 this.locked = false;
23458 * Returns true if the selections are locked.
23459 * @return {Boolean}
23461 isLocked : function(){
23462 return this.locked;
23466 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23467 * @class Roo.bootstrap.Table.RowSelectionModel
23468 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23469 * It supports multiple selections and keyboard selection/navigation.
23471 * @param {Object} config
23474 Roo.bootstrap.Table.RowSelectionModel = function(config){
23475 Roo.apply(this, config);
23476 this.selections = new Roo.util.MixedCollection(false, function(o){
23481 this.lastActive = false;
23485 * @event selectionchange
23486 * Fires when the selection changes
23487 * @param {SelectionModel} this
23489 "selectionchange" : true,
23491 * @event afterselectionchange
23492 * Fires after the selection changes (eg. by key press or clicking)
23493 * @param {SelectionModel} this
23495 "afterselectionchange" : true,
23497 * @event beforerowselect
23498 * Fires when a row is selected being selected, return false to cancel.
23499 * @param {SelectionModel} this
23500 * @param {Number} rowIndex The selected index
23501 * @param {Boolean} keepExisting False if other selections will be cleared
23503 "beforerowselect" : true,
23506 * Fires when a row is selected.
23507 * @param {SelectionModel} this
23508 * @param {Number} rowIndex The selected index
23509 * @param {Roo.data.Record} r The record
23511 "rowselect" : true,
23513 * @event rowdeselect
23514 * Fires when a row is deselected.
23515 * @param {SelectionModel} this
23516 * @param {Number} rowIndex The selected index
23518 "rowdeselect" : true
23520 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23521 this.locked = false;
23524 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23526 * @cfg {Boolean} singleSelect
23527 * True to allow selection of only one row at a time (defaults to false)
23529 singleSelect : false,
23532 initEvents : function()
23535 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23536 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23537 //}else{ // allow click to work like normal
23538 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23540 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23541 this.grid.on("rowclick", this.handleMouseDown, this);
23543 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23544 "up" : function(e){
23546 this.selectPrevious(e.shiftKey);
23547 }else if(this.last !== false && this.lastActive !== false){
23548 var last = this.last;
23549 this.selectRange(this.last, this.lastActive-1);
23550 this.grid.getView().focusRow(this.lastActive);
23551 if(last !== false){
23555 this.selectFirstRow();
23557 this.fireEvent("afterselectionchange", this);
23559 "down" : function(e){
23561 this.selectNext(e.shiftKey);
23562 }else if(this.last !== false && this.lastActive !== false){
23563 var last = this.last;
23564 this.selectRange(this.last, this.lastActive+1);
23565 this.grid.getView().focusRow(this.lastActive);
23566 if(last !== false){
23570 this.selectFirstRow();
23572 this.fireEvent("afterselectionchange", this);
23576 this.grid.store.on('load', function(){
23577 this.selections.clear();
23580 var view = this.grid.view;
23581 view.on("refresh", this.onRefresh, this);
23582 view.on("rowupdated", this.onRowUpdated, this);
23583 view.on("rowremoved", this.onRemove, this);
23588 onRefresh : function()
23590 var ds = this.grid.store, i, v = this.grid.view;
23591 var s = this.selections;
23592 s.each(function(r){
23593 if((i = ds.indexOfId(r.id)) != -1){
23602 onRemove : function(v, index, r){
23603 this.selections.remove(r);
23607 onRowUpdated : function(v, index, r){
23608 if(this.isSelected(r)){
23609 v.onRowSelect(index);
23615 * @param {Array} records The records to select
23616 * @param {Boolean} keepExisting (optional) True to keep existing selections
23618 selectRecords : function(records, keepExisting)
23621 this.clearSelections();
23623 var ds = this.grid.store;
23624 for(var i = 0, len = records.length; i < len; i++){
23625 this.selectRow(ds.indexOf(records[i]), true);
23630 * Gets the number of selected rows.
23633 getCount : function(){
23634 return this.selections.length;
23638 * Selects the first row in the grid.
23640 selectFirstRow : function(){
23645 * Select the last row.
23646 * @param {Boolean} keepExisting (optional) True to keep existing selections
23648 selectLastRow : function(keepExisting){
23649 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23650 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23654 * Selects the row immediately following the last selected row.
23655 * @param {Boolean} keepExisting (optional) True to keep existing selections
23657 selectNext : function(keepExisting)
23659 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23660 this.selectRow(this.last+1, keepExisting);
23661 this.grid.getView().focusRow(this.last);
23666 * Selects the row that precedes the last selected row.
23667 * @param {Boolean} keepExisting (optional) True to keep existing selections
23669 selectPrevious : function(keepExisting){
23671 this.selectRow(this.last-1, keepExisting);
23672 this.grid.getView().focusRow(this.last);
23677 * Returns the selected records
23678 * @return {Array} Array of selected records
23680 getSelections : function(){
23681 return [].concat(this.selections.items);
23685 * Returns the first selected record.
23688 getSelected : function(){
23689 return this.selections.itemAt(0);
23694 * Clears all selections.
23696 clearSelections : function(fast)
23702 var ds = this.grid.store;
23703 var s = this.selections;
23704 s.each(function(r){
23705 this.deselectRow(ds.indexOfId(r.id));
23709 this.selections.clear();
23716 * Selects all rows.
23718 selectAll : function(){
23722 this.selections.clear();
23723 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23724 this.selectRow(i, true);
23729 * Returns True if there is a selection.
23730 * @return {Boolean}
23732 hasSelection : function(){
23733 return this.selections.length > 0;
23737 * Returns True if the specified row is selected.
23738 * @param {Number/Record} record The record or index of the record to check
23739 * @return {Boolean}
23741 isSelected : function(index){
23742 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23743 return (r && this.selections.key(r.id) ? true : false);
23747 * Returns True if the specified record id is selected.
23748 * @param {String} id The id of record to check
23749 * @return {Boolean}
23751 isIdSelected : function(id){
23752 return (this.selections.key(id) ? true : false);
23757 handleMouseDBClick : function(e, t){
23761 handleMouseDown : function(e, t)
23763 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23764 if(this.isLocked() || rowIndex < 0 ){
23767 if(e.shiftKey && this.last !== false){
23768 var last = this.last;
23769 this.selectRange(last, rowIndex, e.ctrlKey);
23770 this.last = last; // reset the last
23774 var isSelected = this.isSelected(rowIndex);
23775 //Roo.log("select row:" + rowIndex);
23777 this.deselectRow(rowIndex);
23779 this.selectRow(rowIndex, true);
23783 if(e.button !== 0 && isSelected){
23784 alert('rowIndex 2: ' + rowIndex);
23785 view.focusRow(rowIndex);
23786 }else if(e.ctrlKey && isSelected){
23787 this.deselectRow(rowIndex);
23788 }else if(!isSelected){
23789 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23790 view.focusRow(rowIndex);
23794 this.fireEvent("afterselectionchange", this);
23797 handleDragableRowClick : function(grid, rowIndex, e)
23799 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23800 this.selectRow(rowIndex, false);
23801 grid.view.focusRow(rowIndex);
23802 this.fireEvent("afterselectionchange", this);
23807 * Selects multiple rows.
23808 * @param {Array} rows Array of the indexes of the row to select
23809 * @param {Boolean} keepExisting (optional) True to keep existing selections
23811 selectRows : function(rows, keepExisting){
23813 this.clearSelections();
23815 for(var i = 0, len = rows.length; i < len; i++){
23816 this.selectRow(rows[i], true);
23821 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23822 * @param {Number} startRow The index of the first row in the range
23823 * @param {Number} endRow The index of the last row in the range
23824 * @param {Boolean} keepExisting (optional) True to retain existing selections
23826 selectRange : function(startRow, endRow, keepExisting){
23831 this.clearSelections();
23833 if(startRow <= endRow){
23834 for(var i = startRow; i <= endRow; i++){
23835 this.selectRow(i, true);
23838 for(var i = startRow; i >= endRow; i--){
23839 this.selectRow(i, true);
23845 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23846 * @param {Number} startRow The index of the first row in the range
23847 * @param {Number} endRow The index of the last row in the range
23849 deselectRange : function(startRow, endRow, preventViewNotify){
23853 for(var i = startRow; i <= endRow; i++){
23854 this.deselectRow(i, preventViewNotify);
23860 * @param {Number} row The index of the row to select
23861 * @param {Boolean} keepExisting (optional) True to keep existing selections
23863 selectRow : function(index, keepExisting, preventViewNotify)
23865 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23868 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23869 if(!keepExisting || this.singleSelect){
23870 this.clearSelections();
23873 var r = this.grid.store.getAt(index);
23874 //console.log('selectRow - record id :' + r.id);
23876 this.selections.add(r);
23877 this.last = this.lastActive = index;
23878 if(!preventViewNotify){
23879 var proxy = new Roo.Element(
23880 this.grid.getRowDom(index)
23882 proxy.addClass('bg-info info');
23884 this.fireEvent("rowselect", this, index, r);
23885 this.fireEvent("selectionchange", this);
23891 * @param {Number} row The index of the row to deselect
23893 deselectRow : function(index, preventViewNotify)
23898 if(this.last == index){
23901 if(this.lastActive == index){
23902 this.lastActive = false;
23905 var r = this.grid.store.getAt(index);
23910 this.selections.remove(r);
23911 //.console.log('deselectRow - record id :' + r.id);
23912 if(!preventViewNotify){
23914 var proxy = new Roo.Element(
23915 this.grid.getRowDom(index)
23917 proxy.removeClass('bg-info info');
23919 this.fireEvent("rowdeselect", this, index);
23920 this.fireEvent("selectionchange", this);
23924 restoreLast : function(){
23926 this.last = this._last;
23931 acceptsNav : function(row, col, cm){
23932 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23936 onEditorKey : function(field, e){
23937 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23942 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23944 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23946 }else if(k == e.ENTER && !e.ctrlKey){
23950 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23952 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23954 }else if(k == e.ESC){
23958 g.startEditing(newCell[0], newCell[1]);
23964 * Ext JS Library 1.1.1
23965 * Copyright(c) 2006-2007, Ext JS, LLC.
23967 * Originally Released Under LGPL - original licence link has changed is not relivant.
23970 * <script type="text/javascript">
23974 * @class Roo.bootstrap.PagingToolbar
23975 * @extends Roo.bootstrap.NavSimplebar
23976 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23978 * Create a new PagingToolbar
23979 * @param {Object} config The config object
23980 * @param {Roo.data.Store} store
23982 Roo.bootstrap.PagingToolbar = function(config)
23984 // old args format still supported... - xtype is prefered..
23985 // created from xtype...
23987 this.ds = config.dataSource;
23989 if (config.store && !this.ds) {
23990 this.store= Roo.factory(config.store, Roo.data);
23991 this.ds = this.store;
23992 this.ds.xmodule = this.xmodule || false;
23995 this.toolbarItems = [];
23996 if (config.items) {
23997 this.toolbarItems = config.items;
24000 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24005 this.bind(this.ds);
24008 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24012 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24014 * @cfg {Roo.data.Store} dataSource
24015 * The underlying data store providing the paged data
24018 * @cfg {String/HTMLElement/Element} container
24019 * container The id or element that will contain the toolbar
24022 * @cfg {Boolean} displayInfo
24023 * True to display the displayMsg (defaults to false)
24026 * @cfg {Number} pageSize
24027 * The number of records to display per page (defaults to 20)
24031 * @cfg {String} displayMsg
24032 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24034 displayMsg : 'Displaying {0} - {1} of {2}',
24036 * @cfg {String} emptyMsg
24037 * The message to display when no records are found (defaults to "No data to display")
24039 emptyMsg : 'No data to display',
24041 * Customizable piece of the default paging text (defaults to "Page")
24044 beforePageText : "Page",
24046 * Customizable piece of the default paging text (defaults to "of %0")
24049 afterPageText : "of {0}",
24051 * Customizable piece of the default paging text (defaults to "First Page")
24054 firstText : "First Page",
24056 * Customizable piece of the default paging text (defaults to "Previous Page")
24059 prevText : "Previous Page",
24061 * Customizable piece of the default paging text (defaults to "Next Page")
24064 nextText : "Next Page",
24066 * Customizable piece of the default paging text (defaults to "Last Page")
24069 lastText : "Last Page",
24071 * Customizable piece of the default paging text (defaults to "Refresh")
24074 refreshText : "Refresh",
24078 onRender : function(ct, position)
24080 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24081 this.navgroup.parentId = this.id;
24082 this.navgroup.onRender(this.el, null);
24083 // add the buttons to the navgroup
24085 if(this.displayInfo){
24086 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24087 this.displayEl = this.el.select('.x-paging-info', true).first();
24088 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24089 // this.displayEl = navel.el.select('span',true).first();
24095 Roo.each(_this.buttons, function(e){ // this might need to use render????
24096 Roo.factory(e).onRender(_this.el, null);
24100 Roo.each(_this.toolbarItems, function(e) {
24101 _this.navgroup.addItem(e);
24105 this.first = this.navgroup.addItem({
24106 tooltip: this.firstText,
24108 icon : 'fa fa-backward',
24110 preventDefault: true,
24111 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24114 this.prev = this.navgroup.addItem({
24115 tooltip: this.prevText,
24117 icon : 'fa fa-step-backward',
24119 preventDefault: true,
24120 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24122 //this.addSeparator();
24125 var field = this.navgroup.addItem( {
24127 cls : 'x-paging-position',
24129 html : this.beforePageText +
24130 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24131 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24134 this.field = field.el.select('input', true).first();
24135 this.field.on("keydown", this.onPagingKeydown, this);
24136 this.field.on("focus", function(){this.dom.select();});
24139 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24140 //this.field.setHeight(18);
24141 //this.addSeparator();
24142 this.next = this.navgroup.addItem({
24143 tooltip: this.nextText,
24145 html : ' <i class="fa fa-step-forward">',
24147 preventDefault: true,
24148 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24150 this.last = this.navgroup.addItem({
24151 tooltip: this.lastText,
24152 icon : 'fa fa-forward',
24155 preventDefault: true,
24156 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24158 //this.addSeparator();
24159 this.loading = this.navgroup.addItem({
24160 tooltip: this.refreshText,
24161 icon: 'fa fa-refresh',
24162 preventDefault: true,
24163 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24169 updateInfo : function(){
24170 if(this.displayEl){
24171 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24172 var msg = count == 0 ?
24176 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24178 this.displayEl.update(msg);
24183 onLoad : function(ds, r, o){
24184 this.cursor = o.params ? o.params.start : 0;
24185 var d = this.getPageData(),
24189 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24190 this.field.dom.value = ap;
24191 this.first.setDisabled(ap == 1);
24192 this.prev.setDisabled(ap == 1);
24193 this.next.setDisabled(ap == ps);
24194 this.last.setDisabled(ap == ps);
24195 this.loading.enable();
24200 getPageData : function(){
24201 var total = this.ds.getTotalCount();
24204 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24205 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24210 onLoadError : function(){
24211 this.loading.enable();
24215 onPagingKeydown : function(e){
24216 var k = e.getKey();
24217 var d = this.getPageData();
24219 var v = this.field.dom.value, pageNum;
24220 if(!v || isNaN(pageNum = parseInt(v, 10))){
24221 this.field.dom.value = d.activePage;
24224 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24225 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24228 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))
24230 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24231 this.field.dom.value = pageNum;
24232 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24235 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24237 var v = this.field.dom.value, pageNum;
24238 var increment = (e.shiftKey) ? 10 : 1;
24239 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24242 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24243 this.field.dom.value = d.activePage;
24246 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24248 this.field.dom.value = parseInt(v, 10) + increment;
24249 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24250 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24257 beforeLoad : function(){
24259 this.loading.disable();
24264 onClick : function(which){
24273 ds.load({params:{start: 0, limit: this.pageSize}});
24276 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24279 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24282 var total = ds.getTotalCount();
24283 var extra = total % this.pageSize;
24284 var lastStart = extra ? (total - extra) : total-this.pageSize;
24285 ds.load({params:{start: lastStart, limit: this.pageSize}});
24288 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24294 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24295 * @param {Roo.data.Store} store The data store to unbind
24297 unbind : function(ds){
24298 ds.un("beforeload", this.beforeLoad, this);
24299 ds.un("load", this.onLoad, this);
24300 ds.un("loadexception", this.onLoadError, this);
24301 ds.un("remove", this.updateInfo, this);
24302 ds.un("add", this.updateInfo, this);
24303 this.ds = undefined;
24307 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24308 * @param {Roo.data.Store} store The data store to bind
24310 bind : function(ds){
24311 ds.on("beforeload", this.beforeLoad, this);
24312 ds.on("load", this.onLoad, this);
24313 ds.on("loadexception", this.onLoadError, this);
24314 ds.on("remove", this.updateInfo, this);
24315 ds.on("add", this.updateInfo, this);
24326 * @class Roo.bootstrap.MessageBar
24327 * @extends Roo.bootstrap.Component
24328 * Bootstrap MessageBar class
24329 * @cfg {String} html contents of the MessageBar
24330 * @cfg {String} weight (info | success | warning | danger) default info
24331 * @cfg {String} beforeClass insert the bar before the given class
24332 * @cfg {Boolean} closable (true | false) default false
24333 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24336 * Create a new Element
24337 * @param {Object} config The config object
24340 Roo.bootstrap.MessageBar = function(config){
24341 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24344 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24350 beforeClass: 'bootstrap-sticky-wrap',
24352 getAutoCreate : function(){
24356 cls: 'alert alert-dismissable alert-' + this.weight,
24361 html: this.html || ''
24367 cfg.cls += ' alert-messages-fixed';
24381 onRender : function(ct, position)
24383 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24386 var cfg = Roo.apply({}, this.getAutoCreate());
24390 cfg.cls += ' ' + this.cls;
24393 cfg.style = this.style;
24395 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24397 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24400 this.el.select('>button.close').on('click', this.hide, this);
24406 if (!this.rendered) {
24412 this.fireEvent('show', this);
24418 if (!this.rendered) {
24424 this.fireEvent('hide', this);
24427 update : function()
24429 // var e = this.el.dom.firstChild;
24431 // if(this.closable){
24432 // e = e.nextSibling;
24435 // e.data = this.html || '';
24437 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24453 * @class Roo.bootstrap.Graph
24454 * @extends Roo.bootstrap.Component
24455 * Bootstrap Graph class
24459 @cfg {String} graphtype bar | vbar | pie
24460 @cfg {number} g_x coodinator | centre x (pie)
24461 @cfg {number} g_y coodinator | centre y (pie)
24462 @cfg {number} g_r radius (pie)
24463 @cfg {number} g_height height of the chart (respected by all elements in the set)
24464 @cfg {number} g_width width of the chart (respected by all elements in the set)
24465 @cfg {Object} title The title of the chart
24468 -opts (object) options for the chart
24470 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24471 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24473 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.
24474 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24476 o stretch (boolean)
24478 -opts (object) options for the pie
24481 o startAngle (number)
24482 o endAngle (number)
24486 * Create a new Input
24487 * @param {Object} config The config object
24490 Roo.bootstrap.Graph = function(config){
24491 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24497 * The img click event for the img.
24498 * @param {Roo.EventObject} e
24504 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24515 //g_colors: this.colors,
24522 getAutoCreate : function(){
24533 onRender : function(ct,position){
24536 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24538 if (typeof(Raphael) == 'undefined') {
24539 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24543 this.raphael = Raphael(this.el.dom);
24545 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24546 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24547 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24548 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24550 r.text(160, 10, "Single Series Chart").attr(txtattr);
24551 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24552 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24553 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24555 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24556 r.barchart(330, 10, 300, 220, data1);
24557 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24558 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24561 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24562 // r.barchart(30, 30, 560, 250, xdata, {
24563 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24564 // axis : "0 0 1 1",
24565 // axisxlabels : xdata
24566 // //yvalues : cols,
24569 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24571 // this.load(null,xdata,{
24572 // axis : "0 0 1 1",
24573 // axisxlabels : xdata
24578 load : function(graphtype,xdata,opts)
24580 this.raphael.clear();
24582 graphtype = this.graphtype;
24587 var r = this.raphael,
24588 fin = function () {
24589 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24591 fout = function () {
24592 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24594 pfin = function() {
24595 this.sector.stop();
24596 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24599 this.label[0].stop();
24600 this.label[0].attr({ r: 7.5 });
24601 this.label[1].attr({ "font-weight": 800 });
24604 pfout = function() {
24605 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24608 this.label[0].animate({ r: 5 }, 500, "bounce");
24609 this.label[1].attr({ "font-weight": 400 });
24615 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24618 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24621 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24622 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24624 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24631 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24636 setTitle: function(o)
24641 initEvents: function() {
24644 this.el.on('click', this.onClick, this);
24648 onClick : function(e)
24650 Roo.log('img onclick');
24651 this.fireEvent('click', this, e);
24663 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24666 * @class Roo.bootstrap.dash.NumberBox
24667 * @extends Roo.bootstrap.Component
24668 * Bootstrap NumberBox class
24669 * @cfg {String} headline Box headline
24670 * @cfg {String} content Box content
24671 * @cfg {String} icon Box icon
24672 * @cfg {String} footer Footer text
24673 * @cfg {String} fhref Footer href
24676 * Create a new NumberBox
24677 * @param {Object} config The config object
24681 Roo.bootstrap.dash.NumberBox = function(config){
24682 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24686 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24695 getAutoCreate : function(){
24699 cls : 'small-box ',
24707 cls : 'roo-headline',
24708 html : this.headline
24712 cls : 'roo-content',
24713 html : this.content
24727 cls : 'ion ' + this.icon
24736 cls : 'small-box-footer',
24737 href : this.fhref || '#',
24741 cfg.cn.push(footer);
24748 onRender : function(ct,position){
24749 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24756 setHeadline: function (value)
24758 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24761 setFooter: function (value, href)
24763 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24766 this.el.select('a.small-box-footer',true).first().attr('href', href);
24771 setContent: function (value)
24773 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24776 initEvents: function()
24790 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24793 * @class Roo.bootstrap.dash.TabBox
24794 * @extends Roo.bootstrap.Component
24795 * Bootstrap TabBox class
24796 * @cfg {String} title Title of the TabBox
24797 * @cfg {String} icon Icon of the TabBox
24798 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24799 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24802 * Create a new TabBox
24803 * @param {Object} config The config object
24807 Roo.bootstrap.dash.TabBox = function(config){
24808 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24813 * When a pane is added
24814 * @param {Roo.bootstrap.dash.TabPane} pane
24818 * @event activatepane
24819 * When a pane is activated
24820 * @param {Roo.bootstrap.dash.TabPane} pane
24822 "activatepane" : true
24830 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24835 tabScrollable : false,
24837 getChildContainer : function()
24839 return this.el.select('.tab-content', true).first();
24842 getAutoCreate : function(){
24846 cls: 'pull-left header',
24854 cls: 'fa ' + this.icon
24860 cls: 'nav nav-tabs pull-right',
24866 if(this.tabScrollable){
24873 cls: 'nav nav-tabs pull-right',
24884 cls: 'nav-tabs-custom',
24889 cls: 'tab-content no-padding',
24897 initEvents : function()
24899 //Roo.log('add add pane handler');
24900 this.on('addpane', this.onAddPane, this);
24903 * Updates the box title
24904 * @param {String} html to set the title to.
24906 setTitle : function(value)
24908 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24910 onAddPane : function(pane)
24912 this.panes.push(pane);
24913 //Roo.log('addpane');
24915 // tabs are rendere left to right..
24916 if(!this.showtabs){
24920 var ctr = this.el.select('.nav-tabs', true).first();
24923 var existing = ctr.select('.nav-tab',true);
24924 var qty = existing.getCount();;
24927 var tab = ctr.createChild({
24929 cls : 'nav-tab' + (qty ? '' : ' active'),
24937 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24940 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24942 pane.el.addClass('active');
24947 onTabClick : function(ev,un,ob,pane)
24949 //Roo.log('tab - prev default');
24950 ev.preventDefault();
24953 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24954 pane.tab.addClass('active');
24955 //Roo.log(pane.title);
24956 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24957 // technically we should have a deactivate event.. but maybe add later.
24958 // and it should not de-activate the selected tab...
24959 this.fireEvent('activatepane', pane);
24960 pane.el.addClass('active');
24961 pane.fireEvent('activate');
24966 getActivePane : function()
24969 Roo.each(this.panes, function(p) {
24970 if(p.el.hasClass('active')){
24991 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24993 * @class Roo.bootstrap.TabPane
24994 * @extends Roo.bootstrap.Component
24995 * Bootstrap TabPane class
24996 * @cfg {Boolean} active (false | true) Default false
24997 * @cfg {String} title title of panel
25001 * Create a new TabPane
25002 * @param {Object} config The config object
25005 Roo.bootstrap.dash.TabPane = function(config){
25006 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25012 * When a pane is activated
25013 * @param {Roo.bootstrap.dash.TabPane} pane
25020 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25025 // the tabBox that this is attached to.
25028 getAutoCreate : function()
25036 cfg.cls += ' active';
25041 initEvents : function()
25043 //Roo.log('trigger add pane handler');
25044 this.parent().fireEvent('addpane', this)
25048 * Updates the tab title
25049 * @param {String} html to set the title to.
25051 setTitle: function(str)
25057 this.tab.select('a', true).first().dom.innerHTML = str;
25074 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25077 * @class Roo.bootstrap.menu.Menu
25078 * @extends Roo.bootstrap.Component
25079 * Bootstrap Menu class - container for Menu
25080 * @cfg {String} html Text of the menu
25081 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25082 * @cfg {String} icon Font awesome icon
25083 * @cfg {String} pos Menu align to (top | bottom) default bottom
25087 * Create a new Menu
25088 * @param {Object} config The config object
25092 Roo.bootstrap.menu.Menu = function(config){
25093 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25097 * @event beforeshow
25098 * Fires before this menu is displayed
25099 * @param {Roo.bootstrap.menu.Menu} this
25103 * @event beforehide
25104 * Fires before this menu is hidden
25105 * @param {Roo.bootstrap.menu.Menu} this
25110 * Fires after this menu is displayed
25111 * @param {Roo.bootstrap.menu.Menu} this
25116 * Fires after this menu is hidden
25117 * @param {Roo.bootstrap.menu.Menu} this
25122 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25123 * @param {Roo.bootstrap.menu.Menu} this
25124 * @param {Roo.EventObject} e
25131 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25135 weight : 'default',
25140 getChildContainer : function() {
25141 if(this.isSubMenu){
25145 return this.el.select('ul.dropdown-menu', true).first();
25148 getAutoCreate : function()
25153 cls : 'roo-menu-text',
25161 cls : 'fa ' + this.icon
25172 cls : 'dropdown-button btn btn-' + this.weight,
25177 cls : 'dropdown-toggle btn btn-' + this.weight,
25187 cls : 'dropdown-menu'
25193 if(this.pos == 'top'){
25194 cfg.cls += ' dropup';
25197 if(this.isSubMenu){
25200 cls : 'dropdown-menu'
25207 onRender : function(ct, position)
25209 this.isSubMenu = ct.hasClass('dropdown-submenu');
25211 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25214 initEvents : function()
25216 if(this.isSubMenu){
25220 this.hidden = true;
25222 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25223 this.triggerEl.on('click', this.onTriggerPress, this);
25225 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25226 this.buttonEl.on('click', this.onClick, this);
25232 if(this.isSubMenu){
25236 return this.el.select('ul.dropdown-menu', true).first();
25239 onClick : function(e)
25241 this.fireEvent("click", this, e);
25244 onTriggerPress : function(e)
25246 if (this.isVisible()) {
25253 isVisible : function(){
25254 return !this.hidden;
25259 this.fireEvent("beforeshow", this);
25261 this.hidden = false;
25262 this.el.addClass('open');
25264 Roo.get(document).on("mouseup", this.onMouseUp, this);
25266 this.fireEvent("show", this);
25273 this.fireEvent("beforehide", this);
25275 this.hidden = true;
25276 this.el.removeClass('open');
25278 Roo.get(document).un("mouseup", this.onMouseUp);
25280 this.fireEvent("hide", this);
25283 onMouseUp : function()
25297 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25300 * @class Roo.bootstrap.menu.Item
25301 * @extends Roo.bootstrap.Component
25302 * Bootstrap MenuItem class
25303 * @cfg {Boolean} submenu (true | false) default false
25304 * @cfg {String} html text of the item
25305 * @cfg {String} href the link
25306 * @cfg {Boolean} disable (true | false) default false
25307 * @cfg {Boolean} preventDefault (true | false) default true
25308 * @cfg {String} icon Font awesome icon
25309 * @cfg {String} pos Submenu align to (left | right) default right
25313 * Create a new Item
25314 * @param {Object} config The config object
25318 Roo.bootstrap.menu.Item = function(config){
25319 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25323 * Fires when the mouse is hovering over this menu
25324 * @param {Roo.bootstrap.menu.Item} this
25325 * @param {Roo.EventObject} e
25330 * Fires when the mouse exits this menu
25331 * @param {Roo.bootstrap.menu.Item} this
25332 * @param {Roo.EventObject} e
25338 * The raw click event for the entire grid.
25339 * @param {Roo.EventObject} e
25345 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25350 preventDefault: true,
25355 getAutoCreate : function()
25360 cls : 'roo-menu-item-text',
25368 cls : 'fa ' + this.icon
25377 href : this.href || '#',
25384 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25388 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25390 if(this.pos == 'left'){
25391 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25398 initEvents : function()
25400 this.el.on('mouseover', this.onMouseOver, this);
25401 this.el.on('mouseout', this.onMouseOut, this);
25403 this.el.select('a', true).first().on('click', this.onClick, this);
25407 onClick : function(e)
25409 if(this.preventDefault){
25410 e.preventDefault();
25413 this.fireEvent("click", this, e);
25416 onMouseOver : function(e)
25418 if(this.submenu && this.pos == 'left'){
25419 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25422 this.fireEvent("mouseover", this, e);
25425 onMouseOut : function(e)
25427 this.fireEvent("mouseout", this, e);
25439 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25442 * @class Roo.bootstrap.menu.Separator
25443 * @extends Roo.bootstrap.Component
25444 * Bootstrap Separator class
25447 * Create a new Separator
25448 * @param {Object} config The config object
25452 Roo.bootstrap.menu.Separator = function(config){
25453 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25456 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25458 getAutoCreate : function(){
25479 * @class Roo.bootstrap.Tooltip
25480 * Bootstrap Tooltip class
25481 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25482 * to determine which dom element triggers the tooltip.
25484 * It needs to add support for additional attributes like tooltip-position
25487 * Create a new Toolti
25488 * @param {Object} config The config object
25491 Roo.bootstrap.Tooltip = function(config){
25492 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25494 this.alignment = Roo.bootstrap.Tooltip.alignment;
25496 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25497 this.alignment = config.alignment;
25502 Roo.apply(Roo.bootstrap.Tooltip, {
25504 * @function init initialize tooltip monitoring.
25508 currentTip : false,
25509 currentRegion : false,
25515 Roo.get(document).on('mouseover', this.enter ,this);
25516 Roo.get(document).on('mouseout', this.leave, this);
25519 this.currentTip = new Roo.bootstrap.Tooltip();
25522 enter : function(ev)
25524 var dom = ev.getTarget();
25526 //Roo.log(['enter',dom]);
25527 var el = Roo.fly(dom);
25528 if (this.currentEl) {
25530 //Roo.log(this.currentEl);
25531 //Roo.log(this.currentEl.contains(dom));
25532 if (this.currentEl == el) {
25535 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25541 if (this.currentTip.el) {
25542 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25546 if(!el || el.dom == document){
25552 // you can not look for children, as if el is the body.. then everythign is the child..
25553 if (!el.attr('tooltip')) { //
25554 if (!el.select("[tooltip]").elements.length) {
25557 // is the mouse over this child...?
25558 bindEl = el.select("[tooltip]").first();
25559 var xy = ev.getXY();
25560 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25561 //Roo.log("not in region.");
25564 //Roo.log("child element over..");
25567 this.currentEl = bindEl;
25568 this.currentTip.bind(bindEl);
25569 this.currentRegion = Roo.lib.Region.getRegion(dom);
25570 this.currentTip.enter();
25573 leave : function(ev)
25575 var dom = ev.getTarget();
25576 //Roo.log(['leave',dom]);
25577 if (!this.currentEl) {
25582 if (dom != this.currentEl.dom) {
25585 var xy = ev.getXY();
25586 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25589 // only activate leave if mouse cursor is outside... bounding box..
25594 if (this.currentTip) {
25595 this.currentTip.leave();
25597 //Roo.log('clear currentEl');
25598 this.currentEl = false;
25603 'left' : ['r-l', [-2,0], 'right'],
25604 'right' : ['l-r', [2,0], 'left'],
25605 'bottom' : ['t-b', [0,2], 'top'],
25606 'top' : [ 'b-t', [0,-2], 'bottom']
25612 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25617 delay : null, // can be { show : 300 , hide: 500}
25621 hoverState : null, //???
25623 placement : 'bottom',
25627 getAutoCreate : function(){
25634 cls : 'tooltip-arrow'
25637 cls : 'tooltip-inner'
25644 bind : function(el)
25650 enter : function () {
25652 if (this.timeout != null) {
25653 clearTimeout(this.timeout);
25656 this.hoverState = 'in';
25657 //Roo.log("enter - show");
25658 if (!this.delay || !this.delay.show) {
25663 this.timeout = setTimeout(function () {
25664 if (_t.hoverState == 'in') {
25667 }, this.delay.show);
25671 clearTimeout(this.timeout);
25673 this.hoverState = 'out';
25674 if (!this.delay || !this.delay.hide) {
25680 this.timeout = setTimeout(function () {
25681 //Roo.log("leave - timeout");
25683 if (_t.hoverState == 'out') {
25685 Roo.bootstrap.Tooltip.currentEl = false;
25690 show : function (msg)
25693 this.render(document.body);
25696 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25698 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25700 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25702 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25704 var placement = typeof this.placement == 'function' ?
25705 this.placement.call(this, this.el, on_el) :
25708 var autoToken = /\s?auto?\s?/i;
25709 var autoPlace = autoToken.test(placement);
25711 placement = placement.replace(autoToken, '') || 'top';
25715 //this.el.setXY([0,0]);
25717 //this.el.dom.style.display='block';
25719 //this.el.appendTo(on_el);
25721 var p = this.getPosition();
25722 var box = this.el.getBox();
25728 var align = this.alignment[placement];
25730 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25732 if(placement == 'top' || placement == 'bottom'){
25734 placement = 'right';
25737 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25738 placement = 'left';
25741 var scroll = Roo.select('body', true).first().getScroll();
25743 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25749 this.el.alignTo(this.bindEl, align[0],align[1]);
25750 //var arrow = this.el.select('.arrow',true).first();
25751 //arrow.set(align[2],
25753 this.el.addClass(placement);
25755 this.el.addClass('in fade');
25757 this.hoverState = null;
25759 if (this.el.hasClass('fade')) {
25770 //this.el.setXY([0,0]);
25771 this.el.removeClass('in');
25787 * @class Roo.bootstrap.LocationPicker
25788 * @extends Roo.bootstrap.Component
25789 * Bootstrap LocationPicker class
25790 * @cfg {Number} latitude Position when init default 0
25791 * @cfg {Number} longitude Position when init default 0
25792 * @cfg {Number} zoom default 15
25793 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25794 * @cfg {Boolean} mapTypeControl default false
25795 * @cfg {Boolean} disableDoubleClickZoom default false
25796 * @cfg {Boolean} scrollwheel default true
25797 * @cfg {Boolean} streetViewControl default false
25798 * @cfg {Number} radius default 0
25799 * @cfg {String} locationName
25800 * @cfg {Boolean} draggable default true
25801 * @cfg {Boolean} enableAutocomplete default false
25802 * @cfg {Boolean} enableReverseGeocode default true
25803 * @cfg {String} markerTitle
25806 * Create a new LocationPicker
25807 * @param {Object} config The config object
25811 Roo.bootstrap.LocationPicker = function(config){
25813 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25818 * Fires when the picker initialized.
25819 * @param {Roo.bootstrap.LocationPicker} this
25820 * @param {Google Location} location
25824 * @event positionchanged
25825 * Fires when the picker position changed.
25826 * @param {Roo.bootstrap.LocationPicker} this
25827 * @param {Google Location} location
25829 positionchanged : true,
25832 * Fires when the map resize.
25833 * @param {Roo.bootstrap.LocationPicker} this
25838 * Fires when the map show.
25839 * @param {Roo.bootstrap.LocationPicker} this
25844 * Fires when the map hide.
25845 * @param {Roo.bootstrap.LocationPicker} this
25850 * Fires when click the map.
25851 * @param {Roo.bootstrap.LocationPicker} this
25852 * @param {Map event} e
25856 * @event mapRightClick
25857 * Fires when right click the map.
25858 * @param {Roo.bootstrap.LocationPicker} this
25859 * @param {Map event} e
25861 mapRightClick : true,
25863 * @event markerClick
25864 * Fires when click the marker.
25865 * @param {Roo.bootstrap.LocationPicker} this
25866 * @param {Map event} e
25868 markerClick : true,
25870 * @event markerRightClick
25871 * Fires when right click the marker.
25872 * @param {Roo.bootstrap.LocationPicker} this
25873 * @param {Map event} e
25875 markerRightClick : true,
25877 * @event OverlayViewDraw
25878 * Fires when OverlayView Draw
25879 * @param {Roo.bootstrap.LocationPicker} this
25881 OverlayViewDraw : true,
25883 * @event OverlayViewOnAdd
25884 * Fires when OverlayView Draw
25885 * @param {Roo.bootstrap.LocationPicker} this
25887 OverlayViewOnAdd : true,
25889 * @event OverlayViewOnRemove
25890 * Fires when OverlayView Draw
25891 * @param {Roo.bootstrap.LocationPicker} this
25893 OverlayViewOnRemove : true,
25895 * @event OverlayViewShow
25896 * Fires when OverlayView Draw
25897 * @param {Roo.bootstrap.LocationPicker} this
25898 * @param {Pixel} cpx
25900 OverlayViewShow : true,
25902 * @event OverlayViewHide
25903 * Fires when OverlayView Draw
25904 * @param {Roo.bootstrap.LocationPicker} this
25906 OverlayViewHide : true,
25908 * @event loadexception
25909 * Fires when load google lib failed.
25910 * @param {Roo.bootstrap.LocationPicker} this
25912 loadexception : true
25917 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25919 gMapContext: false,
25925 mapTypeControl: false,
25926 disableDoubleClickZoom: false,
25928 streetViewControl: false,
25932 enableAutocomplete: false,
25933 enableReverseGeocode: true,
25936 getAutoCreate: function()
25941 cls: 'roo-location-picker'
25947 initEvents: function(ct, position)
25949 if(!this.el.getWidth() || this.isApplied()){
25953 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25958 initial: function()
25960 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25961 this.fireEvent('loadexception', this);
25965 if(!this.mapTypeId){
25966 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25969 this.gMapContext = this.GMapContext();
25971 this.initOverlayView();
25973 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25977 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25978 _this.setPosition(_this.gMapContext.marker.position);
25981 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25982 _this.fireEvent('mapClick', this, event);
25986 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25987 _this.fireEvent('mapRightClick', this, event);
25991 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25992 _this.fireEvent('markerClick', this, event);
25996 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25997 _this.fireEvent('markerRightClick', this, event);
26001 this.setPosition(this.gMapContext.location);
26003 this.fireEvent('initial', this, this.gMapContext.location);
26006 initOverlayView: function()
26010 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26014 _this.fireEvent('OverlayViewDraw', _this);
26019 _this.fireEvent('OverlayViewOnAdd', _this);
26022 onRemove: function()
26024 _this.fireEvent('OverlayViewOnRemove', _this);
26027 show: function(cpx)
26029 _this.fireEvent('OverlayViewShow', _this, cpx);
26034 _this.fireEvent('OverlayViewHide', _this);
26040 fromLatLngToContainerPixel: function(event)
26042 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26045 isApplied: function()
26047 return this.getGmapContext() == false ? false : true;
26050 getGmapContext: function()
26052 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26055 GMapContext: function()
26057 var position = new google.maps.LatLng(this.latitude, this.longitude);
26059 var _map = new google.maps.Map(this.el.dom, {
26062 mapTypeId: this.mapTypeId,
26063 mapTypeControl: this.mapTypeControl,
26064 disableDoubleClickZoom: this.disableDoubleClickZoom,
26065 scrollwheel: this.scrollwheel,
26066 streetViewControl: this.streetViewControl,
26067 locationName: this.locationName,
26068 draggable: this.draggable,
26069 enableAutocomplete: this.enableAutocomplete,
26070 enableReverseGeocode: this.enableReverseGeocode
26073 var _marker = new google.maps.Marker({
26074 position: position,
26076 title: this.markerTitle,
26077 draggable: this.draggable
26084 location: position,
26085 radius: this.radius,
26086 locationName: this.locationName,
26087 addressComponents: {
26088 formatted_address: null,
26089 addressLine1: null,
26090 addressLine2: null,
26092 streetNumber: null,
26096 stateOrProvince: null
26099 domContainer: this.el.dom,
26100 geodecoder: new google.maps.Geocoder()
26104 drawCircle: function(center, radius, options)
26106 if (this.gMapContext.circle != null) {
26107 this.gMapContext.circle.setMap(null);
26111 options = Roo.apply({}, options, {
26112 strokeColor: "#0000FF",
26113 strokeOpacity: .35,
26115 fillColor: "#0000FF",
26119 options.map = this.gMapContext.map;
26120 options.radius = radius;
26121 options.center = center;
26122 this.gMapContext.circle = new google.maps.Circle(options);
26123 return this.gMapContext.circle;
26129 setPosition: function(location)
26131 this.gMapContext.location = location;
26132 this.gMapContext.marker.setPosition(location);
26133 this.gMapContext.map.panTo(location);
26134 this.drawCircle(location, this.gMapContext.radius, {});
26138 if (this.gMapContext.settings.enableReverseGeocode) {
26139 this.gMapContext.geodecoder.geocode({
26140 latLng: this.gMapContext.location
26141 }, function(results, status) {
26143 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26144 _this.gMapContext.locationName = results[0].formatted_address;
26145 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26147 _this.fireEvent('positionchanged', this, location);
26154 this.fireEvent('positionchanged', this, location);
26159 google.maps.event.trigger(this.gMapContext.map, "resize");
26161 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26163 this.fireEvent('resize', this);
26166 setPositionByLatLng: function(latitude, longitude)
26168 this.setPosition(new google.maps.LatLng(latitude, longitude));
26171 getCurrentPosition: function()
26174 latitude: this.gMapContext.location.lat(),
26175 longitude: this.gMapContext.location.lng()
26179 getAddressName: function()
26181 return this.gMapContext.locationName;
26184 getAddressComponents: function()
26186 return this.gMapContext.addressComponents;
26189 address_component_from_google_geocode: function(address_components)
26193 for (var i = 0; i < address_components.length; i++) {
26194 var component = address_components[i];
26195 if (component.types.indexOf("postal_code") >= 0) {
26196 result.postalCode = component.short_name;
26197 } else if (component.types.indexOf("street_number") >= 0) {
26198 result.streetNumber = component.short_name;
26199 } else if (component.types.indexOf("route") >= 0) {
26200 result.streetName = component.short_name;
26201 } else if (component.types.indexOf("neighborhood") >= 0) {
26202 result.city = component.short_name;
26203 } else if (component.types.indexOf("locality") >= 0) {
26204 result.city = component.short_name;
26205 } else if (component.types.indexOf("sublocality") >= 0) {
26206 result.district = component.short_name;
26207 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26208 result.stateOrProvince = component.short_name;
26209 } else if (component.types.indexOf("country") >= 0) {
26210 result.country = component.short_name;
26214 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26215 result.addressLine2 = "";
26219 setZoomLevel: function(zoom)
26221 this.gMapContext.map.setZoom(zoom);
26234 this.fireEvent('show', this);
26245 this.fireEvent('hide', this);
26250 Roo.apply(Roo.bootstrap.LocationPicker, {
26252 OverlayView : function(map, options)
26254 options = options || {};
26268 * @class Roo.bootstrap.Alert
26269 * @extends Roo.bootstrap.Component
26270 * Bootstrap Alert class
26271 * @cfg {String} title The title of alert
26272 * @cfg {String} html The content of alert
26273 * @cfg {String} weight ( success | info | warning | danger )
26274 * @cfg {String} faicon font-awesomeicon
26277 * Create a new alert
26278 * @param {Object} config The config object
26282 Roo.bootstrap.Alert = function(config){
26283 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26287 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26294 getAutoCreate : function()
26303 cls : 'roo-alert-icon'
26308 cls : 'roo-alert-title',
26313 cls : 'roo-alert-text',
26320 cfg.cn[0].cls += ' fa ' + this.faicon;
26324 cfg.cls += ' alert-' + this.weight;
26330 initEvents: function()
26332 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26335 setTitle : function(str)
26337 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26340 setText : function(str)
26342 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26345 setWeight : function(weight)
26348 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26351 this.weight = weight;
26353 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26356 setIcon : function(icon)
26359 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26362 this.faicon = icon;
26364 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26385 * @class Roo.bootstrap.UploadCropbox
26386 * @extends Roo.bootstrap.Component
26387 * Bootstrap UploadCropbox class
26388 * @cfg {String} emptyText show when image has been loaded
26389 * @cfg {String} rotateNotify show when image too small to rotate
26390 * @cfg {Number} errorTimeout default 3000
26391 * @cfg {Number} minWidth default 300
26392 * @cfg {Number} minHeight default 300
26393 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26394 * @cfg {Boolean} isDocument (true|false) default false
26395 * @cfg {String} url action url
26396 * @cfg {String} paramName default 'imageUpload'
26397 * @cfg {String} method default POST
26398 * @cfg {Boolean} loadMask (true|false) default true
26399 * @cfg {Boolean} loadingText default 'Loading...'
26402 * Create a new UploadCropbox
26403 * @param {Object} config The config object
26406 Roo.bootstrap.UploadCropbox = function(config){
26407 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26411 * @event beforeselectfile
26412 * Fire before select file
26413 * @param {Roo.bootstrap.UploadCropbox} this
26415 "beforeselectfile" : true,
26418 * Fire after initEvent
26419 * @param {Roo.bootstrap.UploadCropbox} this
26424 * Fire after initEvent
26425 * @param {Roo.bootstrap.UploadCropbox} this
26426 * @param {String} data
26431 * Fire when preparing the file data
26432 * @param {Roo.bootstrap.UploadCropbox} this
26433 * @param {Object} file
26438 * Fire when get exception
26439 * @param {Roo.bootstrap.UploadCropbox} this
26440 * @param {XMLHttpRequest} xhr
26442 "exception" : true,
26444 * @event beforeloadcanvas
26445 * Fire before load the canvas
26446 * @param {Roo.bootstrap.UploadCropbox} this
26447 * @param {String} src
26449 "beforeloadcanvas" : true,
26452 * Fire when trash image
26453 * @param {Roo.bootstrap.UploadCropbox} this
26458 * Fire when download the image
26459 * @param {Roo.bootstrap.UploadCropbox} this
26463 * @event footerbuttonclick
26464 * Fire when footerbuttonclick
26465 * @param {Roo.bootstrap.UploadCropbox} this
26466 * @param {String} type
26468 "footerbuttonclick" : true,
26472 * @param {Roo.bootstrap.UploadCropbox} this
26477 * Fire when rotate the image
26478 * @param {Roo.bootstrap.UploadCropbox} this
26479 * @param {String} pos
26484 * Fire when inspect the file
26485 * @param {Roo.bootstrap.UploadCropbox} this
26486 * @param {Object} file
26491 * Fire when xhr upload the file
26492 * @param {Roo.bootstrap.UploadCropbox} this
26493 * @param {Object} data
26498 * Fire when arrange the file data
26499 * @param {Roo.bootstrap.UploadCropbox} this
26500 * @param {Object} formData
26505 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26508 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26510 emptyText : 'Click to upload image',
26511 rotateNotify : 'Image is too small to rotate',
26512 errorTimeout : 3000,
26526 cropType : 'image/jpeg',
26528 canvasLoaded : false,
26529 isDocument : false,
26531 paramName : 'imageUpload',
26533 loadingText : 'Loading...',
26536 getAutoCreate : function()
26540 cls : 'roo-upload-cropbox',
26544 cls : 'roo-upload-cropbox-selector',
26549 cls : 'roo-upload-cropbox-body',
26550 style : 'cursor:pointer',
26554 cls : 'roo-upload-cropbox-preview'
26558 cls : 'roo-upload-cropbox-thumb'
26562 cls : 'roo-upload-cropbox-empty-notify',
26563 html : this.emptyText
26567 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26568 html : this.rotateNotify
26574 cls : 'roo-upload-cropbox-footer',
26577 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26587 onRender : function(ct, position)
26589 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26591 if (this.buttons.length) {
26593 Roo.each(this.buttons, function(bb) {
26595 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26597 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26603 this.maskEl = this.el;
26607 initEvents : function()
26609 this.urlAPI = (window.createObjectURL && window) ||
26610 (window.URL && URL.revokeObjectURL && URL) ||
26611 (window.webkitURL && webkitURL);
26613 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26614 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26616 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26617 this.selectorEl.hide();
26619 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26620 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26622 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26623 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26624 this.thumbEl.hide();
26626 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26627 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26629 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26630 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26631 this.errorEl.hide();
26633 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26634 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26635 this.footerEl.hide();
26637 this.setThumbBoxSize();
26643 this.fireEvent('initial', this);
26650 window.addEventListener("resize", function() { _this.resize(); } );
26652 this.bodyEl.on('click', this.beforeSelectFile, this);
26655 this.bodyEl.on('touchstart', this.onTouchStart, this);
26656 this.bodyEl.on('touchmove', this.onTouchMove, this);
26657 this.bodyEl.on('touchend', this.onTouchEnd, this);
26661 this.bodyEl.on('mousedown', this.onMouseDown, this);
26662 this.bodyEl.on('mousemove', this.onMouseMove, this);
26663 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26664 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26665 Roo.get(document).on('mouseup', this.onMouseUp, this);
26668 this.selectorEl.on('change', this.onFileSelected, this);
26674 this.baseScale = 1;
26676 this.baseRotate = 1;
26677 this.dragable = false;
26678 this.pinching = false;
26681 this.cropData = false;
26682 this.notifyEl.dom.innerHTML = this.emptyText;
26684 this.selectorEl.dom.value = '';
26688 resize : function()
26690 if(this.fireEvent('resize', this) != false){
26691 this.setThumbBoxPosition();
26692 this.setCanvasPosition();
26696 onFooterButtonClick : function(e, el, o, type)
26699 case 'rotate-left' :
26700 this.onRotateLeft(e);
26702 case 'rotate-right' :
26703 this.onRotateRight(e);
26706 this.beforeSelectFile(e);
26721 this.fireEvent('footerbuttonclick', this, type);
26724 beforeSelectFile : function(e)
26726 e.preventDefault();
26728 if(this.fireEvent('beforeselectfile', this) != false){
26729 this.selectorEl.dom.click();
26733 onFileSelected : function(e)
26735 e.preventDefault();
26737 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26741 var file = this.selectorEl.dom.files[0];
26743 if(this.fireEvent('inspect', this, file) != false){
26744 this.prepare(file);
26749 trash : function(e)
26751 this.fireEvent('trash', this);
26754 download : function(e)
26756 this.fireEvent('download', this);
26759 loadCanvas : function(src)
26761 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26765 this.imageEl = document.createElement('img');
26769 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26771 this.imageEl.src = src;
26775 onLoadCanvas : function()
26777 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26778 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26780 this.bodyEl.un('click', this.beforeSelectFile, this);
26782 this.notifyEl.hide();
26783 this.thumbEl.show();
26784 this.footerEl.show();
26786 this.baseRotateLevel();
26788 if(this.isDocument){
26789 this.setThumbBoxSize();
26792 this.setThumbBoxPosition();
26794 this.baseScaleLevel();
26800 this.canvasLoaded = true;
26803 this.maskEl.unmask();
26808 setCanvasPosition : function()
26810 if(!this.canvasEl){
26814 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26815 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26817 this.previewEl.setLeft(pw);
26818 this.previewEl.setTop(ph);
26822 onMouseDown : function(e)
26826 this.dragable = true;
26827 this.pinching = false;
26829 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26830 this.dragable = false;
26834 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26835 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26839 onMouseMove : function(e)
26843 if(!this.canvasLoaded){
26847 if (!this.dragable){
26851 var minX = Math.ceil(this.thumbEl.getLeft(true));
26852 var minY = Math.ceil(this.thumbEl.getTop(true));
26854 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26855 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26857 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26858 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26860 x = x - this.mouseX;
26861 y = y - this.mouseY;
26863 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26864 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26866 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26867 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26869 this.previewEl.setLeft(bgX);
26870 this.previewEl.setTop(bgY);
26872 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26873 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26876 onMouseUp : function(e)
26880 this.dragable = false;
26883 onMouseWheel : function(e)
26887 this.startScale = this.scale;
26889 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26891 if(!this.zoomable()){
26892 this.scale = this.startScale;
26901 zoomable : function()
26903 var minScale = this.thumbEl.getWidth() / this.minWidth;
26905 if(this.minWidth < this.minHeight){
26906 minScale = this.thumbEl.getHeight() / this.minHeight;
26909 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26910 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26914 (this.rotate == 0 || this.rotate == 180) &&
26916 width > this.imageEl.OriginWidth ||
26917 height > this.imageEl.OriginHeight ||
26918 (width < this.minWidth && height < this.minHeight)
26926 (this.rotate == 90 || this.rotate == 270) &&
26928 width > this.imageEl.OriginWidth ||
26929 height > this.imageEl.OriginHeight ||
26930 (width < this.minHeight && height < this.minWidth)
26937 !this.isDocument &&
26938 (this.rotate == 0 || this.rotate == 180) &&
26940 width < this.minWidth ||
26941 width > this.imageEl.OriginWidth ||
26942 height < this.minHeight ||
26943 height > this.imageEl.OriginHeight
26950 !this.isDocument &&
26951 (this.rotate == 90 || this.rotate == 270) &&
26953 width < this.minHeight ||
26954 width > this.imageEl.OriginWidth ||
26955 height < this.minWidth ||
26956 height > this.imageEl.OriginHeight
26966 onRotateLeft : function(e)
26968 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26970 var minScale = this.thumbEl.getWidth() / this.minWidth;
26972 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26973 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26975 this.startScale = this.scale;
26977 while (this.getScaleLevel() < minScale){
26979 this.scale = this.scale + 1;
26981 if(!this.zoomable()){
26986 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26987 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26992 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26999 this.scale = this.startScale;
27001 this.onRotateFail();
27006 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27008 if(this.isDocument){
27009 this.setThumbBoxSize();
27010 this.setThumbBoxPosition();
27011 this.setCanvasPosition();
27016 this.fireEvent('rotate', this, 'left');
27020 onRotateRight : function(e)
27022 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27024 var minScale = this.thumbEl.getWidth() / this.minWidth;
27026 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27027 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27029 this.startScale = this.scale;
27031 while (this.getScaleLevel() < minScale){
27033 this.scale = this.scale + 1;
27035 if(!this.zoomable()){
27040 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27041 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27046 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27053 this.scale = this.startScale;
27055 this.onRotateFail();
27060 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27062 if(this.isDocument){
27063 this.setThumbBoxSize();
27064 this.setThumbBoxPosition();
27065 this.setCanvasPosition();
27070 this.fireEvent('rotate', this, 'right');
27073 onRotateFail : function()
27075 this.errorEl.show(true);
27079 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27084 this.previewEl.dom.innerHTML = '';
27086 var canvasEl = document.createElement("canvas");
27088 var contextEl = canvasEl.getContext("2d");
27090 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27091 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27092 var center = this.imageEl.OriginWidth / 2;
27094 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27095 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27096 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27097 center = this.imageEl.OriginHeight / 2;
27100 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27102 contextEl.translate(center, center);
27103 contextEl.rotate(this.rotate * Math.PI / 180);
27105 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27107 this.canvasEl = document.createElement("canvas");
27109 this.contextEl = this.canvasEl.getContext("2d");
27111 switch (this.rotate) {
27114 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27115 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27117 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27122 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27123 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27125 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27126 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);
27130 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27135 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27136 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27138 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27139 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);
27143 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);
27148 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27149 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27151 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27152 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27156 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);
27163 this.previewEl.appendChild(this.canvasEl);
27165 this.setCanvasPosition();
27170 if(!this.canvasLoaded){
27174 var imageCanvas = document.createElement("canvas");
27176 var imageContext = imageCanvas.getContext("2d");
27178 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27179 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27181 var center = imageCanvas.width / 2;
27183 imageContext.translate(center, center);
27185 imageContext.rotate(this.rotate * Math.PI / 180);
27187 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27189 var canvas = document.createElement("canvas");
27191 var context = canvas.getContext("2d");
27193 canvas.width = this.minWidth;
27194 canvas.height = this.minHeight;
27196 switch (this.rotate) {
27199 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27200 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27202 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27203 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27205 var targetWidth = this.minWidth - 2 * x;
27206 var targetHeight = this.minHeight - 2 * y;
27210 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27211 scale = targetWidth / width;
27214 if(x > 0 && y == 0){
27215 scale = targetHeight / height;
27218 if(x > 0 && y > 0){
27219 scale = targetWidth / width;
27221 if(width < height){
27222 scale = targetHeight / height;
27226 context.scale(scale, scale);
27228 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27229 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27231 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27232 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27234 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27239 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27240 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27242 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27243 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27245 var targetWidth = this.minWidth - 2 * x;
27246 var targetHeight = this.minHeight - 2 * y;
27250 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27251 scale = targetWidth / width;
27254 if(x > 0 && y == 0){
27255 scale = targetHeight / height;
27258 if(x > 0 && y > 0){
27259 scale = targetWidth / width;
27261 if(width < height){
27262 scale = targetHeight / height;
27266 context.scale(scale, scale);
27268 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27269 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27271 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27272 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27274 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27276 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27281 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27282 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27284 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27285 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27287 var targetWidth = this.minWidth - 2 * x;
27288 var targetHeight = this.minHeight - 2 * y;
27292 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27293 scale = targetWidth / width;
27296 if(x > 0 && y == 0){
27297 scale = targetHeight / height;
27300 if(x > 0 && y > 0){
27301 scale = targetWidth / width;
27303 if(width < height){
27304 scale = targetHeight / height;
27308 context.scale(scale, scale);
27310 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27311 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27313 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27314 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27316 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27317 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27319 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27324 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27325 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27327 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27328 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27330 var targetWidth = this.minWidth - 2 * x;
27331 var targetHeight = this.minHeight - 2 * y;
27335 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27336 scale = targetWidth / width;
27339 if(x > 0 && y == 0){
27340 scale = targetHeight / height;
27343 if(x > 0 && y > 0){
27344 scale = targetWidth / width;
27346 if(width < height){
27347 scale = targetHeight / height;
27351 context.scale(scale, scale);
27353 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27354 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27356 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27357 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27359 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27361 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27368 this.cropData = canvas.toDataURL(this.cropType);
27370 if(this.fireEvent('crop', this, this.cropData) !== false){
27371 this.process(this.file, this.cropData);
27378 setThumbBoxSize : function()
27382 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27383 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27384 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27386 this.minWidth = width;
27387 this.minHeight = height;
27389 if(this.rotate == 90 || this.rotate == 270){
27390 this.minWidth = height;
27391 this.minHeight = width;
27396 width = Math.ceil(this.minWidth * height / this.minHeight);
27398 if(this.minWidth > this.minHeight){
27400 height = Math.ceil(this.minHeight * width / this.minWidth);
27403 this.thumbEl.setStyle({
27404 width : width + 'px',
27405 height : height + 'px'
27412 setThumbBoxPosition : function()
27414 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27415 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27417 this.thumbEl.setLeft(x);
27418 this.thumbEl.setTop(y);
27422 baseRotateLevel : function()
27424 this.baseRotate = 1;
27427 typeof(this.exif) != 'undefined' &&
27428 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27429 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27431 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27434 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27438 baseScaleLevel : function()
27442 if(this.isDocument){
27444 if(this.baseRotate == 6 || this.baseRotate == 8){
27446 height = this.thumbEl.getHeight();
27447 this.baseScale = height / this.imageEl.OriginWidth;
27449 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27450 width = this.thumbEl.getWidth();
27451 this.baseScale = width / this.imageEl.OriginHeight;
27457 height = this.thumbEl.getHeight();
27458 this.baseScale = height / this.imageEl.OriginHeight;
27460 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27461 width = this.thumbEl.getWidth();
27462 this.baseScale = width / this.imageEl.OriginWidth;
27468 if(this.baseRotate == 6 || this.baseRotate == 8){
27470 width = this.thumbEl.getHeight();
27471 this.baseScale = width / this.imageEl.OriginHeight;
27473 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27474 height = this.thumbEl.getWidth();
27475 this.baseScale = height / this.imageEl.OriginHeight;
27478 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27479 height = this.thumbEl.getWidth();
27480 this.baseScale = height / this.imageEl.OriginHeight;
27482 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27483 width = this.thumbEl.getHeight();
27484 this.baseScale = width / this.imageEl.OriginWidth;
27491 width = this.thumbEl.getWidth();
27492 this.baseScale = width / this.imageEl.OriginWidth;
27494 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27495 height = this.thumbEl.getHeight();
27496 this.baseScale = height / this.imageEl.OriginHeight;
27499 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27501 height = this.thumbEl.getHeight();
27502 this.baseScale = height / this.imageEl.OriginHeight;
27504 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27505 width = this.thumbEl.getWidth();
27506 this.baseScale = width / this.imageEl.OriginWidth;
27514 getScaleLevel : function()
27516 return this.baseScale * Math.pow(1.1, this.scale);
27519 onTouchStart : function(e)
27521 if(!this.canvasLoaded){
27522 this.beforeSelectFile(e);
27526 var touches = e.browserEvent.touches;
27532 if(touches.length == 1){
27533 this.onMouseDown(e);
27537 if(touches.length != 2){
27543 for(var i = 0, finger; finger = touches[i]; i++){
27544 coords.push(finger.pageX, finger.pageY);
27547 var x = Math.pow(coords[0] - coords[2], 2);
27548 var y = Math.pow(coords[1] - coords[3], 2);
27550 this.startDistance = Math.sqrt(x + y);
27552 this.startScale = this.scale;
27554 this.pinching = true;
27555 this.dragable = false;
27559 onTouchMove : function(e)
27561 if(!this.pinching && !this.dragable){
27565 var touches = e.browserEvent.touches;
27572 this.onMouseMove(e);
27578 for(var i = 0, finger; finger = touches[i]; i++){
27579 coords.push(finger.pageX, finger.pageY);
27582 var x = Math.pow(coords[0] - coords[2], 2);
27583 var y = Math.pow(coords[1] - coords[3], 2);
27585 this.endDistance = Math.sqrt(x + y);
27587 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27589 if(!this.zoomable()){
27590 this.scale = this.startScale;
27598 onTouchEnd : function(e)
27600 this.pinching = false;
27601 this.dragable = false;
27605 process : function(file, crop)
27608 this.maskEl.mask(this.loadingText);
27611 this.xhr = new XMLHttpRequest();
27613 file.xhr = this.xhr;
27615 this.xhr.open(this.method, this.url, true);
27618 "Accept": "application/json",
27619 "Cache-Control": "no-cache",
27620 "X-Requested-With": "XMLHttpRequest"
27623 for (var headerName in headers) {
27624 var headerValue = headers[headerName];
27626 this.xhr.setRequestHeader(headerName, headerValue);
27632 this.xhr.onload = function()
27634 _this.xhrOnLoad(_this.xhr);
27637 this.xhr.onerror = function()
27639 _this.xhrOnError(_this.xhr);
27642 var formData = new FormData();
27644 formData.append('returnHTML', 'NO');
27647 formData.append('crop', crop);
27650 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27651 formData.append(this.paramName, file, file.name);
27654 if(typeof(file.filename) != 'undefined'){
27655 formData.append('filename', file.filename);
27658 if(typeof(file.mimetype) != 'undefined'){
27659 formData.append('mimetype', file.mimetype);
27662 if(this.fireEvent('arrange', this, formData) != false){
27663 this.xhr.send(formData);
27667 xhrOnLoad : function(xhr)
27670 this.maskEl.unmask();
27673 if (xhr.readyState !== 4) {
27674 this.fireEvent('exception', this, xhr);
27678 var response = Roo.decode(xhr.responseText);
27680 if(!response.success){
27681 this.fireEvent('exception', this, xhr);
27685 var response = Roo.decode(xhr.responseText);
27687 this.fireEvent('upload', this, response);
27691 xhrOnError : function()
27694 this.maskEl.unmask();
27697 Roo.log('xhr on error');
27699 var response = Roo.decode(xhr.responseText);
27705 prepare : function(file)
27708 this.maskEl.mask(this.loadingText);
27714 if(typeof(file) === 'string'){
27715 this.loadCanvas(file);
27719 if(!file || !this.urlAPI){
27724 this.cropType = file.type;
27728 if(this.fireEvent('prepare', this, this.file) != false){
27730 var reader = new FileReader();
27732 reader.onload = function (e) {
27733 if (e.target.error) {
27734 Roo.log(e.target.error);
27738 var buffer = e.target.result,
27739 dataView = new DataView(buffer),
27741 maxOffset = dataView.byteLength - 4,
27745 if (dataView.getUint16(0) === 0xffd8) {
27746 while (offset < maxOffset) {
27747 markerBytes = dataView.getUint16(offset);
27749 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27750 markerLength = dataView.getUint16(offset + 2) + 2;
27751 if (offset + markerLength > dataView.byteLength) {
27752 Roo.log('Invalid meta data: Invalid segment size.');
27756 if(markerBytes == 0xffe1){
27757 _this.parseExifData(
27764 offset += markerLength;
27774 var url = _this.urlAPI.createObjectURL(_this.file);
27776 _this.loadCanvas(url);
27781 reader.readAsArrayBuffer(this.file);
27787 parseExifData : function(dataView, offset, length)
27789 var tiffOffset = offset + 10,
27793 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27794 // No Exif data, might be XMP data instead
27798 // Check for the ASCII code for "Exif" (0x45786966):
27799 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27800 // No Exif data, might be XMP data instead
27803 if (tiffOffset + 8 > dataView.byteLength) {
27804 Roo.log('Invalid Exif data: Invalid segment size.');
27807 // Check for the two null bytes:
27808 if (dataView.getUint16(offset + 8) !== 0x0000) {
27809 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27812 // Check the byte alignment:
27813 switch (dataView.getUint16(tiffOffset)) {
27815 littleEndian = true;
27818 littleEndian = false;
27821 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27824 // Check for the TIFF tag marker (0x002A):
27825 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27826 Roo.log('Invalid Exif data: Missing TIFF marker.');
27829 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27830 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27832 this.parseExifTags(
27835 tiffOffset + dirOffset,
27840 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27845 if (dirOffset + 6 > dataView.byteLength) {
27846 Roo.log('Invalid Exif data: Invalid directory offset.');
27849 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27850 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27851 if (dirEndOffset + 4 > dataView.byteLength) {
27852 Roo.log('Invalid Exif data: Invalid directory size.');
27855 for (i = 0; i < tagsNumber; i += 1) {
27859 dirOffset + 2 + 12 * i, // tag offset
27863 // Return the offset to the next directory:
27864 return dataView.getUint32(dirEndOffset, littleEndian);
27867 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27869 var tag = dataView.getUint16(offset, littleEndian);
27871 this.exif[tag] = this.getExifValue(
27875 dataView.getUint16(offset + 2, littleEndian), // tag type
27876 dataView.getUint32(offset + 4, littleEndian), // tag length
27881 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27883 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27892 Roo.log('Invalid Exif data: Invalid tag type.');
27896 tagSize = tagType.size * length;
27897 // Determine if the value is contained in the dataOffset bytes,
27898 // or if the value at the dataOffset is a pointer to the actual data:
27899 dataOffset = tagSize > 4 ?
27900 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27901 if (dataOffset + tagSize > dataView.byteLength) {
27902 Roo.log('Invalid Exif data: Invalid data offset.');
27905 if (length === 1) {
27906 return tagType.getValue(dataView, dataOffset, littleEndian);
27909 for (i = 0; i < length; i += 1) {
27910 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27913 if (tagType.ascii) {
27915 // Concatenate the chars:
27916 for (i = 0; i < values.length; i += 1) {
27918 // Ignore the terminating NULL byte(s):
27919 if (c === '\u0000') {
27931 Roo.apply(Roo.bootstrap.UploadCropbox, {
27933 'Orientation': 0x0112
27937 1: 0, //'top-left',
27939 3: 180, //'bottom-right',
27940 // 4: 'bottom-left',
27942 6: 90, //'right-top',
27943 // 7: 'right-bottom',
27944 8: 270 //'left-bottom'
27948 // byte, 8-bit unsigned int:
27950 getValue: function (dataView, dataOffset) {
27951 return dataView.getUint8(dataOffset);
27955 // ascii, 8-bit byte:
27957 getValue: function (dataView, dataOffset) {
27958 return String.fromCharCode(dataView.getUint8(dataOffset));
27963 // short, 16 bit int:
27965 getValue: function (dataView, dataOffset, littleEndian) {
27966 return dataView.getUint16(dataOffset, littleEndian);
27970 // long, 32 bit int:
27972 getValue: function (dataView, dataOffset, littleEndian) {
27973 return dataView.getUint32(dataOffset, littleEndian);
27977 // rational = two long values, first is numerator, second is denominator:
27979 getValue: function (dataView, dataOffset, littleEndian) {
27980 return dataView.getUint32(dataOffset, littleEndian) /
27981 dataView.getUint32(dataOffset + 4, littleEndian);
27985 // slong, 32 bit signed int:
27987 getValue: function (dataView, dataOffset, littleEndian) {
27988 return dataView.getInt32(dataOffset, littleEndian);
27992 // srational, two slongs, first is numerator, second is denominator:
27994 getValue: function (dataView, dataOffset, littleEndian) {
27995 return dataView.getInt32(dataOffset, littleEndian) /
27996 dataView.getInt32(dataOffset + 4, littleEndian);
28006 cls : 'btn-group roo-upload-cropbox-rotate-left',
28007 action : 'rotate-left',
28011 cls : 'btn btn-default',
28012 html : '<i class="fa fa-undo"></i>'
28018 cls : 'btn-group roo-upload-cropbox-picture',
28019 action : 'picture',
28023 cls : 'btn btn-default',
28024 html : '<i class="fa fa-picture-o"></i>'
28030 cls : 'btn-group roo-upload-cropbox-rotate-right',
28031 action : 'rotate-right',
28035 cls : 'btn btn-default',
28036 html : '<i class="fa fa-repeat"></i>'
28044 cls : 'btn-group roo-upload-cropbox-rotate-left',
28045 action : 'rotate-left',
28049 cls : 'btn btn-default',
28050 html : '<i class="fa fa-undo"></i>'
28056 cls : 'btn-group roo-upload-cropbox-download',
28057 action : 'download',
28061 cls : 'btn btn-default',
28062 html : '<i class="fa fa-download"></i>'
28068 cls : 'btn-group roo-upload-cropbox-crop',
28073 cls : 'btn btn-default',
28074 html : '<i class="fa fa-crop"></i>'
28080 cls : 'btn-group roo-upload-cropbox-trash',
28085 cls : 'btn btn-default',
28086 html : '<i class="fa fa-trash"></i>'
28092 cls : 'btn-group roo-upload-cropbox-rotate-right',
28093 action : 'rotate-right',
28097 cls : 'btn btn-default',
28098 html : '<i class="fa fa-repeat"></i>'
28106 cls : 'btn-group roo-upload-cropbox-rotate-left',
28107 action : 'rotate-left',
28111 cls : 'btn btn-default',
28112 html : '<i class="fa fa-undo"></i>'
28118 cls : 'btn-group roo-upload-cropbox-rotate-right',
28119 action : 'rotate-right',
28123 cls : 'btn btn-default',
28124 html : '<i class="fa fa-repeat"></i>'
28137 * @class Roo.bootstrap.DocumentManager
28138 * @extends Roo.bootstrap.Component
28139 * Bootstrap DocumentManager class
28140 * @cfg {String} paramName default 'imageUpload'
28141 * @cfg {String} toolTipName default 'filename'
28142 * @cfg {String} method default POST
28143 * @cfg {String} url action url
28144 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28145 * @cfg {Boolean} multiple multiple upload default true
28146 * @cfg {Number} thumbSize default 300
28147 * @cfg {String} fieldLabel
28148 * @cfg {Number} labelWidth default 4
28149 * @cfg {String} labelAlign (left|top) default left
28150 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28151 * @cfg {Number} labellg set the width of label (1-12)
28152 * @cfg {Number} labelmd set the width of label (1-12)
28153 * @cfg {Number} labelsm set the width of label (1-12)
28154 * @cfg {Number} labelxs set the width of label (1-12)
28157 * Create a new DocumentManager
28158 * @param {Object} config The config object
28161 Roo.bootstrap.DocumentManager = function(config){
28162 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28165 this.delegates = [];
28170 * Fire when initial the DocumentManager
28171 * @param {Roo.bootstrap.DocumentManager} this
28176 * inspect selected file
28177 * @param {Roo.bootstrap.DocumentManager} this
28178 * @param {File} file
28183 * Fire when xhr load exception
28184 * @param {Roo.bootstrap.DocumentManager} this
28185 * @param {XMLHttpRequest} xhr
28187 "exception" : true,
28189 * @event afterupload
28190 * Fire when xhr load exception
28191 * @param {Roo.bootstrap.DocumentManager} this
28192 * @param {XMLHttpRequest} xhr
28194 "afterupload" : true,
28197 * prepare the form data
28198 * @param {Roo.bootstrap.DocumentManager} this
28199 * @param {Object} formData
28204 * Fire when remove the file
28205 * @param {Roo.bootstrap.DocumentManager} this
28206 * @param {Object} file
28211 * Fire after refresh the file
28212 * @param {Roo.bootstrap.DocumentManager} this
28217 * Fire after click the image
28218 * @param {Roo.bootstrap.DocumentManager} this
28219 * @param {Object} file
28224 * Fire when upload a image and editable set to true
28225 * @param {Roo.bootstrap.DocumentManager} this
28226 * @param {Object} file
28230 * @event beforeselectfile
28231 * Fire before select file
28232 * @param {Roo.bootstrap.DocumentManager} this
28234 "beforeselectfile" : true,
28237 * Fire before process file
28238 * @param {Roo.bootstrap.DocumentManager} this
28239 * @param {Object} file
28246 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28255 paramName : 'imageUpload',
28256 toolTipName : 'filename',
28259 labelAlign : 'left',
28269 getAutoCreate : function()
28271 var managerWidget = {
28273 cls : 'roo-document-manager',
28277 cls : 'roo-document-manager-selector',
28282 cls : 'roo-document-manager-uploader',
28286 cls : 'roo-document-manager-upload-btn',
28287 html : '<i class="fa fa-plus"></i>'
28298 cls : 'column col-md-12',
28303 if(this.fieldLabel.length){
28308 cls : 'column col-md-12',
28309 html : this.fieldLabel
28313 cls : 'column col-md-12',
28318 if(this.labelAlign == 'left'){
28323 html : this.fieldLabel
28332 if(this.labelWidth > 12){
28333 content[0].style = "width: " + this.labelWidth + 'px';
28336 if(this.labelWidth < 13 && this.labelmd == 0){
28337 this.labelmd = this.labelWidth;
28340 if(this.labellg > 0){
28341 content[0].cls += ' col-lg-' + this.labellg;
28342 content[1].cls += ' col-lg-' + (12 - this.labellg);
28345 if(this.labelmd > 0){
28346 content[0].cls += ' col-md-' + this.labelmd;
28347 content[1].cls += ' col-md-' + (12 - this.labelmd);
28350 if(this.labelsm > 0){
28351 content[0].cls += ' col-sm-' + this.labelsm;
28352 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28355 if(this.labelxs > 0){
28356 content[0].cls += ' col-xs-' + this.labelxs;
28357 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28365 cls : 'row clearfix',
28373 initEvents : function()
28375 this.managerEl = this.el.select('.roo-document-manager', true).first();
28376 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28378 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28379 this.selectorEl.hide();
28382 this.selectorEl.attr('multiple', 'multiple');
28385 this.selectorEl.on('change', this.onFileSelected, this);
28387 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28388 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28390 this.uploader.on('click', this.onUploaderClick, this);
28392 this.renderProgressDialog();
28396 window.addEventListener("resize", function() { _this.refresh(); } );
28398 this.fireEvent('initial', this);
28401 renderProgressDialog : function()
28405 this.progressDialog = new Roo.bootstrap.Modal({
28406 cls : 'roo-document-manager-progress-dialog',
28407 allow_close : false,
28417 btnclick : function() {
28418 _this.uploadCancel();
28424 this.progressDialog.render(Roo.get(document.body));
28426 this.progress = new Roo.bootstrap.Progress({
28427 cls : 'roo-document-manager-progress',
28432 this.progress.render(this.progressDialog.getChildContainer());
28434 this.progressBar = new Roo.bootstrap.ProgressBar({
28435 cls : 'roo-document-manager-progress-bar',
28438 aria_valuemax : 12,
28442 this.progressBar.render(this.progress.getChildContainer());
28445 onUploaderClick : function(e)
28447 e.preventDefault();
28449 if(this.fireEvent('beforeselectfile', this) != false){
28450 this.selectorEl.dom.click();
28455 onFileSelected : function(e)
28457 e.preventDefault();
28459 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28463 Roo.each(this.selectorEl.dom.files, function(file){
28464 if(this.fireEvent('inspect', this, file) != false){
28465 this.files.push(file);
28475 this.selectorEl.dom.value = '';
28477 if(!this.files.length){
28481 if(this.boxes > 0 && this.files.length > this.boxes){
28482 this.files = this.files.slice(0, this.boxes);
28485 this.uploader.show();
28487 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28488 this.uploader.hide();
28497 Roo.each(this.files, function(file){
28499 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28500 var f = this.renderPreview(file);
28505 if(file.type.indexOf('image') != -1){
28506 this.delegates.push(
28508 _this.process(file);
28509 }).createDelegate(this)
28517 _this.process(file);
28518 }).createDelegate(this)
28523 this.files = files;
28525 this.delegates = this.delegates.concat(docs);
28527 if(!this.delegates.length){
28532 this.progressBar.aria_valuemax = this.delegates.length;
28539 arrange : function()
28541 if(!this.delegates.length){
28542 this.progressDialog.hide();
28547 var delegate = this.delegates.shift();
28549 this.progressDialog.show();
28551 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28553 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28558 refresh : function()
28560 this.uploader.show();
28562 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28563 this.uploader.hide();
28566 Roo.isTouch ? this.closable(false) : this.closable(true);
28568 this.fireEvent('refresh', this);
28571 onRemove : function(e, el, o)
28573 e.preventDefault();
28575 this.fireEvent('remove', this, o);
28579 remove : function(o)
28583 Roo.each(this.files, function(file){
28584 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28593 this.files = files;
28600 Roo.each(this.files, function(file){
28605 file.target.remove();
28614 onClick : function(e, el, o)
28616 e.preventDefault();
28618 this.fireEvent('click', this, o);
28622 closable : function(closable)
28624 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28626 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28638 xhrOnLoad : function(xhr)
28640 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28644 if (xhr.readyState !== 4) {
28646 this.fireEvent('exception', this, xhr);
28650 var response = Roo.decode(xhr.responseText);
28652 if(!response.success){
28654 this.fireEvent('exception', this, xhr);
28658 var file = this.renderPreview(response.data);
28660 this.files.push(file);
28664 this.fireEvent('afterupload', this, xhr);
28668 xhrOnError : function(xhr)
28670 Roo.log('xhr on error');
28672 var response = Roo.decode(xhr.responseText);
28679 process : function(file)
28681 if(this.fireEvent('process', this, file) !== false){
28682 if(this.editable && file.type.indexOf('image') != -1){
28683 this.fireEvent('edit', this, file);
28687 this.uploadStart(file, false);
28694 uploadStart : function(file, crop)
28696 this.xhr = new XMLHttpRequest();
28698 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28703 file.xhr = this.xhr;
28705 this.managerEl.createChild({
28707 cls : 'roo-document-manager-loading',
28711 tooltip : file.name,
28712 cls : 'roo-document-manager-thumb',
28713 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28719 this.xhr.open(this.method, this.url, true);
28722 "Accept": "application/json",
28723 "Cache-Control": "no-cache",
28724 "X-Requested-With": "XMLHttpRequest"
28727 for (var headerName in headers) {
28728 var headerValue = headers[headerName];
28730 this.xhr.setRequestHeader(headerName, headerValue);
28736 this.xhr.onload = function()
28738 _this.xhrOnLoad(_this.xhr);
28741 this.xhr.onerror = function()
28743 _this.xhrOnError(_this.xhr);
28746 var formData = new FormData();
28748 formData.append('returnHTML', 'NO');
28751 formData.append('crop', crop);
28754 formData.append(this.paramName, file, file.name);
28761 if(this.fireEvent('prepare', this, formData, options) != false){
28763 if(options.manually){
28767 this.xhr.send(formData);
28771 this.uploadCancel();
28774 uploadCancel : function()
28780 this.delegates = [];
28782 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28789 renderPreview : function(file)
28791 if(typeof(file.target) != 'undefined' && file.target){
28795 var previewEl = this.managerEl.createChild({
28797 cls : 'roo-document-manager-preview',
28801 tooltip : file[this.toolTipName],
28802 cls : 'roo-document-manager-thumb',
28803 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28808 html : '<i class="fa fa-times-circle"></i>'
28813 var close = previewEl.select('button.close', true).first();
28815 close.on('click', this.onRemove, this, file);
28817 file.target = previewEl;
28819 var image = previewEl.select('img', true).first();
28823 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28825 image.on('click', this.onClick, this, file);
28831 onPreviewLoad : function(file, image)
28833 if(typeof(file.target) == 'undefined' || !file.target){
28837 var width = image.dom.naturalWidth || image.dom.width;
28838 var height = image.dom.naturalHeight || image.dom.height;
28840 if(width > height){
28841 file.target.addClass('wide');
28845 file.target.addClass('tall');
28850 uploadFromSource : function(file, crop)
28852 this.xhr = new XMLHttpRequest();
28854 this.managerEl.createChild({
28856 cls : 'roo-document-manager-loading',
28860 tooltip : file.name,
28861 cls : 'roo-document-manager-thumb',
28862 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28868 this.xhr.open(this.method, this.url, true);
28871 "Accept": "application/json",
28872 "Cache-Control": "no-cache",
28873 "X-Requested-With": "XMLHttpRequest"
28876 for (var headerName in headers) {
28877 var headerValue = headers[headerName];
28879 this.xhr.setRequestHeader(headerName, headerValue);
28885 this.xhr.onload = function()
28887 _this.xhrOnLoad(_this.xhr);
28890 this.xhr.onerror = function()
28892 _this.xhrOnError(_this.xhr);
28895 var formData = new FormData();
28897 formData.append('returnHTML', 'NO');
28899 formData.append('crop', crop);
28901 if(typeof(file.filename) != 'undefined'){
28902 formData.append('filename', file.filename);
28905 if(typeof(file.mimetype) != 'undefined'){
28906 formData.append('mimetype', file.mimetype);
28911 if(this.fireEvent('prepare', this, formData) != false){
28912 this.xhr.send(formData);
28922 * @class Roo.bootstrap.DocumentViewer
28923 * @extends Roo.bootstrap.Component
28924 * Bootstrap DocumentViewer class
28925 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28926 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28929 * Create a new DocumentViewer
28930 * @param {Object} config The config object
28933 Roo.bootstrap.DocumentViewer = function(config){
28934 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28939 * Fire after initEvent
28940 * @param {Roo.bootstrap.DocumentViewer} this
28946 * @param {Roo.bootstrap.DocumentViewer} this
28951 * Fire after download button
28952 * @param {Roo.bootstrap.DocumentViewer} this
28957 * Fire after trash button
28958 * @param {Roo.bootstrap.DocumentViewer} this
28965 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28967 showDownload : true,
28971 getAutoCreate : function()
28975 cls : 'roo-document-viewer',
28979 cls : 'roo-document-viewer-body',
28983 cls : 'roo-document-viewer-thumb',
28987 cls : 'roo-document-viewer-image'
28995 cls : 'roo-document-viewer-footer',
28998 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29002 cls : 'btn-group roo-document-viewer-download',
29006 cls : 'btn btn-default',
29007 html : '<i class="fa fa-download"></i>'
29013 cls : 'btn-group roo-document-viewer-trash',
29017 cls : 'btn btn-default',
29018 html : '<i class="fa fa-trash"></i>'
29031 initEvents : function()
29033 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29034 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29036 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29037 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29039 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29040 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29042 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29043 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29045 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29046 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29048 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29049 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29051 this.bodyEl.on('click', this.onClick, this);
29052 this.downloadBtn.on('click', this.onDownload, this);
29053 this.trashBtn.on('click', this.onTrash, this);
29055 this.downloadBtn.hide();
29056 this.trashBtn.hide();
29058 if(this.showDownload){
29059 this.downloadBtn.show();
29062 if(this.showTrash){
29063 this.trashBtn.show();
29066 if(!this.showDownload && !this.showTrash) {
29067 this.footerEl.hide();
29072 initial : function()
29074 this.fireEvent('initial', this);
29078 onClick : function(e)
29080 e.preventDefault();
29082 this.fireEvent('click', this);
29085 onDownload : function(e)
29087 e.preventDefault();
29089 this.fireEvent('download', this);
29092 onTrash : function(e)
29094 e.preventDefault();
29096 this.fireEvent('trash', this);
29108 * @class Roo.bootstrap.NavProgressBar
29109 * @extends Roo.bootstrap.Component
29110 * Bootstrap NavProgressBar class
29113 * Create a new nav progress bar
29114 * @param {Object} config The config object
29117 Roo.bootstrap.NavProgressBar = function(config){
29118 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29120 this.bullets = this.bullets || [];
29122 // Roo.bootstrap.NavProgressBar.register(this);
29126 * Fires when the active item changes
29127 * @param {Roo.bootstrap.NavProgressBar} this
29128 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29129 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29136 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29141 getAutoCreate : function()
29143 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29147 cls : 'roo-navigation-bar-group',
29151 cls : 'roo-navigation-top-bar'
29155 cls : 'roo-navigation-bullets-bar',
29159 cls : 'roo-navigation-bar'
29166 cls : 'roo-navigation-bottom-bar'
29176 initEvents: function()
29181 onRender : function(ct, position)
29183 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29185 if(this.bullets.length){
29186 Roo.each(this.bullets, function(b){
29195 addItem : function(cfg)
29197 var item = new Roo.bootstrap.NavProgressItem(cfg);
29199 item.parentId = this.id;
29200 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29203 var top = new Roo.bootstrap.Element({
29205 cls : 'roo-navigation-bar-text'
29208 var bottom = new Roo.bootstrap.Element({
29210 cls : 'roo-navigation-bar-text'
29213 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29214 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29216 var topText = new Roo.bootstrap.Element({
29218 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29221 var bottomText = new Roo.bootstrap.Element({
29223 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29226 topText.onRender(top.el, null);
29227 bottomText.onRender(bottom.el, null);
29230 item.bottomEl = bottom;
29233 this.barItems.push(item);
29238 getActive : function()
29240 var active = false;
29242 Roo.each(this.barItems, function(v){
29244 if (!v.isActive()) {
29256 setActiveItem : function(item)
29260 Roo.each(this.barItems, function(v){
29261 if (v.rid == item.rid) {
29265 if (v.isActive()) {
29266 v.setActive(false);
29271 item.setActive(true);
29273 this.fireEvent('changed', this, item, prev);
29276 getBarItem: function(rid)
29280 Roo.each(this.barItems, function(e) {
29281 if (e.rid != rid) {
29292 indexOfItem : function(item)
29296 Roo.each(this.barItems, function(v, i){
29298 if (v.rid != item.rid) {
29309 setActiveNext : function()
29311 var i = this.indexOfItem(this.getActive());
29313 if (i > this.barItems.length) {
29317 this.setActiveItem(this.barItems[i+1]);
29320 setActivePrev : function()
29322 var i = this.indexOfItem(this.getActive());
29328 this.setActiveItem(this.barItems[i-1]);
29331 format : function()
29333 if(!this.barItems.length){
29337 var width = 100 / this.barItems.length;
29339 Roo.each(this.barItems, function(i){
29340 i.el.setStyle('width', width + '%');
29341 i.topEl.el.setStyle('width', width + '%');
29342 i.bottomEl.el.setStyle('width', width + '%');
29351 * Nav Progress Item
29356 * @class Roo.bootstrap.NavProgressItem
29357 * @extends Roo.bootstrap.Component
29358 * Bootstrap NavProgressItem class
29359 * @cfg {String} rid the reference id
29360 * @cfg {Boolean} active (true|false) Is item active default false
29361 * @cfg {Boolean} disabled (true|false) Is item active default false
29362 * @cfg {String} html
29363 * @cfg {String} position (top|bottom) text position default bottom
29364 * @cfg {String} icon show icon instead of number
29367 * Create a new NavProgressItem
29368 * @param {Object} config The config object
29370 Roo.bootstrap.NavProgressItem = function(config){
29371 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29376 * The raw click event for the entire grid.
29377 * @param {Roo.bootstrap.NavProgressItem} this
29378 * @param {Roo.EventObject} e
29385 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29391 position : 'bottom',
29394 getAutoCreate : function()
29396 var iconCls = 'roo-navigation-bar-item-icon';
29398 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29402 cls: 'roo-navigation-bar-item',
29412 cfg.cls += ' active';
29415 cfg.cls += ' disabled';
29421 disable : function()
29423 this.setDisabled(true);
29426 enable : function()
29428 this.setDisabled(false);
29431 initEvents: function()
29433 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29435 this.iconEl.on('click', this.onClick, this);
29438 onClick : function(e)
29440 e.preventDefault();
29446 if(this.fireEvent('click', this, e) === false){
29450 this.parent().setActiveItem(this);
29453 isActive: function ()
29455 return this.active;
29458 setActive : function(state)
29460 if(this.active == state){
29464 this.active = state;
29467 this.el.addClass('active');
29471 this.el.removeClass('active');
29476 setDisabled : function(state)
29478 if(this.disabled == state){
29482 this.disabled = state;
29485 this.el.addClass('disabled');
29489 this.el.removeClass('disabled');
29492 tooltipEl : function()
29494 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29507 * @class Roo.bootstrap.FieldLabel
29508 * @extends Roo.bootstrap.Component
29509 * Bootstrap FieldLabel class
29510 * @cfg {String} html contents of the element
29511 * @cfg {String} tag tag of the element default label
29512 * @cfg {String} cls class of the element
29513 * @cfg {String} target label target
29514 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29515 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29516 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29517 * @cfg {String} iconTooltip default "This field is required"
29520 * Create a new FieldLabel
29521 * @param {Object} config The config object
29524 Roo.bootstrap.FieldLabel = function(config){
29525 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29530 * Fires after the field has been marked as invalid.
29531 * @param {Roo.form.FieldLabel} this
29532 * @param {String} msg The validation message
29537 * Fires after the field has been validated with no errors.
29538 * @param {Roo.form.FieldLabel} this
29544 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29551 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29552 validClass : 'text-success fa fa-lg fa-check',
29553 iconTooltip : 'This field is required',
29555 getAutoCreate : function(){
29559 cls : 'roo-bootstrap-field-label ' + this.cls,
29565 tooltip : this.iconTooltip
29577 initEvents: function()
29579 Roo.bootstrap.Element.superclass.initEvents.call(this);
29581 this.iconEl = this.el.select('i', true).first();
29583 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29585 Roo.bootstrap.FieldLabel.register(this);
29589 * Mark this field as valid
29591 markValid : function()
29593 this.iconEl.show();
29595 this.iconEl.removeClass(this.invalidClass);
29597 this.iconEl.addClass(this.validClass);
29599 this.fireEvent('valid', this);
29603 * Mark this field as invalid
29604 * @param {String} msg The validation message
29606 markInvalid : function(msg)
29608 this.iconEl.show();
29610 this.iconEl.removeClass(this.validClass);
29612 this.iconEl.addClass(this.invalidClass);
29614 this.fireEvent('invalid', this, msg);
29620 Roo.apply(Roo.bootstrap.FieldLabel, {
29625 * register a FieldLabel Group
29626 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29628 register : function(label)
29630 if(this.groups.hasOwnProperty(label.target)){
29634 this.groups[label.target] = label;
29638 * fetch a FieldLabel Group based on the target
29639 * @param {string} target
29640 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29642 get: function(target) {
29643 if (typeof(this.groups[target]) == 'undefined') {
29647 return this.groups[target] ;
29656 * page DateSplitField.
29662 * @class Roo.bootstrap.DateSplitField
29663 * @extends Roo.bootstrap.Component
29664 * Bootstrap DateSplitField class
29665 * @cfg {string} fieldLabel - the label associated
29666 * @cfg {Number} labelWidth set the width of label (0-12)
29667 * @cfg {String} labelAlign (top|left)
29668 * @cfg {Boolean} dayAllowBlank (true|false) default false
29669 * @cfg {Boolean} monthAllowBlank (true|false) default false
29670 * @cfg {Boolean} yearAllowBlank (true|false) default false
29671 * @cfg {string} dayPlaceholder
29672 * @cfg {string} monthPlaceholder
29673 * @cfg {string} yearPlaceholder
29674 * @cfg {string} dayFormat default 'd'
29675 * @cfg {string} monthFormat default 'm'
29676 * @cfg {string} yearFormat default 'Y'
29677 * @cfg {Number} labellg set the width of label (1-12)
29678 * @cfg {Number} labelmd set the width of label (1-12)
29679 * @cfg {Number} labelsm set the width of label (1-12)
29680 * @cfg {Number} labelxs set the width of label (1-12)
29684 * Create a new DateSplitField
29685 * @param {Object} config The config object
29688 Roo.bootstrap.DateSplitField = function(config){
29689 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29695 * getting the data of years
29696 * @param {Roo.bootstrap.DateSplitField} this
29697 * @param {Object} years
29702 * getting the data of days
29703 * @param {Roo.bootstrap.DateSplitField} this
29704 * @param {Object} days
29709 * Fires after the field has been marked as invalid.
29710 * @param {Roo.form.Field} this
29711 * @param {String} msg The validation message
29716 * Fires after the field has been validated with no errors.
29717 * @param {Roo.form.Field} this
29723 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29726 labelAlign : 'top',
29728 dayAllowBlank : false,
29729 monthAllowBlank : false,
29730 yearAllowBlank : false,
29731 dayPlaceholder : '',
29732 monthPlaceholder : '',
29733 yearPlaceholder : '',
29737 isFormField : true,
29743 getAutoCreate : function()
29747 cls : 'row roo-date-split-field-group',
29752 cls : 'form-hidden-field roo-date-split-field-group-value',
29758 var labelCls = 'col-md-12';
29759 var contentCls = 'col-md-4';
29761 if(this.fieldLabel){
29765 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29769 html : this.fieldLabel
29774 if(this.labelAlign == 'left'){
29776 if(this.labelWidth > 12){
29777 label.style = "width: " + this.labelWidth + 'px';
29780 if(this.labelWidth < 13 && this.labelmd == 0){
29781 this.labelmd = this.labelWidth;
29784 if(this.labellg > 0){
29785 labelCls = ' col-lg-' + this.labellg;
29786 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29789 if(this.labelmd > 0){
29790 labelCls = ' col-md-' + this.labelmd;
29791 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29794 if(this.labelsm > 0){
29795 labelCls = ' col-sm-' + this.labelsm;
29796 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29799 if(this.labelxs > 0){
29800 labelCls = ' col-xs-' + this.labelxs;
29801 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29805 label.cls += ' ' + labelCls;
29807 cfg.cn.push(label);
29810 Roo.each(['day', 'month', 'year'], function(t){
29813 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29820 inputEl: function ()
29822 return this.el.select('.roo-date-split-field-group-value', true).first();
29825 onRender : function(ct, position)
29829 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29831 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29833 this.dayField = new Roo.bootstrap.ComboBox({
29834 allowBlank : this.dayAllowBlank,
29835 alwaysQuery : true,
29836 displayField : 'value',
29839 forceSelection : true,
29841 placeholder : this.dayPlaceholder,
29842 selectOnFocus : true,
29843 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29844 triggerAction : 'all',
29846 valueField : 'value',
29847 store : new Roo.data.SimpleStore({
29848 data : (function() {
29850 _this.fireEvent('days', _this, days);
29853 fields : [ 'value' ]
29856 select : function (_self, record, index)
29858 _this.setValue(_this.getValue());
29863 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29865 this.monthField = new Roo.bootstrap.MonthField({
29866 after : '<i class=\"fa fa-calendar\"></i>',
29867 allowBlank : this.monthAllowBlank,
29868 placeholder : this.monthPlaceholder,
29871 render : function (_self)
29873 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29874 e.preventDefault();
29878 select : function (_self, oldvalue, newvalue)
29880 _this.setValue(_this.getValue());
29885 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29887 this.yearField = new Roo.bootstrap.ComboBox({
29888 allowBlank : this.yearAllowBlank,
29889 alwaysQuery : true,
29890 displayField : 'value',
29893 forceSelection : true,
29895 placeholder : this.yearPlaceholder,
29896 selectOnFocus : true,
29897 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29898 triggerAction : 'all',
29900 valueField : 'value',
29901 store : new Roo.data.SimpleStore({
29902 data : (function() {
29904 _this.fireEvent('years', _this, years);
29907 fields : [ 'value' ]
29910 select : function (_self, record, index)
29912 _this.setValue(_this.getValue());
29917 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29920 setValue : function(v, format)
29922 this.inputEl.dom.value = v;
29924 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29926 var d = Date.parseDate(v, f);
29933 this.setDay(d.format(this.dayFormat));
29934 this.setMonth(d.format(this.monthFormat));
29935 this.setYear(d.format(this.yearFormat));
29942 setDay : function(v)
29944 this.dayField.setValue(v);
29945 this.inputEl.dom.value = this.getValue();
29950 setMonth : function(v)
29952 this.monthField.setValue(v, true);
29953 this.inputEl.dom.value = this.getValue();
29958 setYear : function(v)
29960 this.yearField.setValue(v);
29961 this.inputEl.dom.value = this.getValue();
29966 getDay : function()
29968 return this.dayField.getValue();
29971 getMonth : function()
29973 return this.monthField.getValue();
29976 getYear : function()
29978 return this.yearField.getValue();
29981 getValue : function()
29983 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29985 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29995 this.inputEl.dom.value = '';
30000 validate : function()
30002 var d = this.dayField.validate();
30003 var m = this.monthField.validate();
30004 var y = this.yearField.validate();
30009 (!this.dayAllowBlank && !d) ||
30010 (!this.monthAllowBlank && !m) ||
30011 (!this.yearAllowBlank && !y)
30016 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30025 this.markInvalid();
30030 markValid : function()
30033 var label = this.el.select('label', true).first();
30034 var icon = this.el.select('i.fa-star', true).first();
30040 this.fireEvent('valid', this);
30044 * Mark this field as invalid
30045 * @param {String} msg The validation message
30047 markInvalid : function(msg)
30050 var label = this.el.select('label', true).first();
30051 var icon = this.el.select('i.fa-star', true).first();
30053 if(label && !icon){
30054 this.el.select('.roo-date-split-field-label', true).createChild({
30056 cls : 'text-danger fa fa-lg fa-star',
30057 tooltip : 'This field is required',
30058 style : 'margin-right:5px;'
30062 this.fireEvent('invalid', this, msg);
30065 clearInvalid : function()
30067 var label = this.el.select('label', true).first();
30068 var icon = this.el.select('i.fa-star', true).first();
30074 this.fireEvent('valid', this);
30077 getName: function()
30087 * http://masonry.desandro.com
30089 * The idea is to render all the bricks based on vertical width...
30091 * The original code extends 'outlayer' - we might need to use that....
30097 * @class Roo.bootstrap.LayoutMasonry
30098 * @extends Roo.bootstrap.Component
30099 * Bootstrap Layout Masonry class
30102 * Create a new Element
30103 * @param {Object} config The config object
30106 Roo.bootstrap.LayoutMasonry = function(config){
30107 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30115 * Fire after layout the items
30116 * @param {Roo.bootstrap.LayoutMasonry} this
30117 * @param {Roo.EventObject} e
30124 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30127 * @cfg {Boolean} isLayoutInstant = no animation?
30129 isLayoutInstant : false, // needed?
30132 * @cfg {Number} boxWidth width of the columns
30137 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30142 * @cfg {Number} padWidth padding below box..
30147 * @cfg {Number} gutter gutter width..
30152 * @cfg {Number} maxCols maximum number of columns
30158 * @cfg {Boolean} isAutoInitial defalut true
30160 isAutoInitial : true,
30165 * @cfg {Boolean} isHorizontal defalut false
30167 isHorizontal : false,
30169 currentSize : null,
30175 bricks: null, //CompositeElement
30179 _isLayoutInited : false,
30181 // isAlternative : false, // only use for vertical layout...
30184 * @cfg {Number} alternativePadWidth padding below box..
30186 alternativePadWidth : 50,
30188 getAutoCreate : function(){
30192 cls: 'blog-masonary-wrapper ' + this.cls,
30194 cls : 'mas-boxes masonary'
30201 getChildContainer: function( )
30203 if (this.boxesEl) {
30204 return this.boxesEl;
30207 this.boxesEl = this.el.select('.mas-boxes').first();
30209 return this.boxesEl;
30213 initEvents : function()
30217 if(this.isAutoInitial){
30218 Roo.log('hook children rendered');
30219 this.on('childrenrendered', function() {
30220 Roo.log('children rendered');
30226 initial : function()
30228 this.currentSize = this.el.getBox(true);
30230 Roo.EventManager.onWindowResize(this.resize, this);
30232 if(!this.isAutoInitial){
30240 //this.layout.defer(500,this);
30244 resize : function()
30246 var cs = this.el.getBox(true);
30249 this.currentSize.width == cs.width &&
30250 this.currentSize.x == cs.x &&
30251 this.currentSize.height == cs.height &&
30252 this.currentSize.y == cs.y
30254 Roo.log("no change in with or X or Y");
30258 this.currentSize = cs;
30264 layout : function()
30266 this._resetLayout();
30268 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30270 this.layoutItems( isInstant );
30272 this._isLayoutInited = true;
30274 this.fireEvent('layout', this);
30278 _resetLayout : function()
30280 if(this.isHorizontal){
30281 this.horizontalMeasureColumns();
30285 this.verticalMeasureColumns();
30289 verticalMeasureColumns : function()
30291 this.getContainerWidth();
30293 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30294 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30298 var boxWidth = this.boxWidth + this.padWidth;
30300 if(this.containerWidth < this.boxWidth){
30301 boxWidth = this.containerWidth
30304 var containerWidth = this.containerWidth;
30306 var cols = Math.floor(containerWidth / boxWidth);
30308 this.cols = Math.max( cols, 1 );
30310 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30312 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30314 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30316 this.colWidth = boxWidth + avail - this.padWidth;
30318 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
30319 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30322 horizontalMeasureColumns : function()
30324 this.getContainerWidth();
30326 var boxWidth = this.boxWidth;
30328 if(this.containerWidth < boxWidth){
30329 boxWidth = this.containerWidth;
30332 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30334 this.el.setHeight(boxWidth);
30338 getContainerWidth : function()
30340 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30343 layoutItems : function( isInstant )
30345 Roo.log(this.bricks);
30347 var items = Roo.apply([], this.bricks);
30349 if(this.isHorizontal){
30350 this._horizontalLayoutItems( items , isInstant );
30354 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30355 // this._verticalAlternativeLayoutItems( items , isInstant );
30359 this._verticalLayoutItems( items , isInstant );
30363 _verticalLayoutItems : function ( items , isInstant)
30365 if ( !items || !items.length ) {
30370 ['xs', 'xs', 'xs', 'tall'],
30371 ['xs', 'xs', 'tall'],
30372 ['xs', 'xs', 'sm'],
30373 ['xs', 'xs', 'xs'],
30379 ['sm', 'xs', 'xs'],
30383 ['tall', 'xs', 'xs', 'xs'],
30384 ['tall', 'xs', 'xs'],
30396 Roo.each(items, function(item, k){
30398 switch (item.size) {
30399 // these layouts take up a full box,
30410 boxes.push([item]);
30433 var filterPattern = function(box, length)
30441 var pattern = box.slice(0, length);
30445 Roo.each(pattern, function(i){
30446 format.push(i.size);
30449 Roo.each(standard, function(s){
30451 if(String(s) != String(format)){
30460 if(!match && length == 1){
30465 filterPattern(box, length - 1);
30469 queue.push(pattern);
30471 box = box.slice(length, box.length);
30473 filterPattern(box, 4);
30479 Roo.each(boxes, function(box, k){
30485 if(box.length == 1){
30490 filterPattern(box, 4);
30494 this._processVerticalLayoutQueue( queue, isInstant );
30498 // _verticalAlternativeLayoutItems : function( items , isInstant )
30500 // if ( !items || !items.length ) {
30504 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30508 _horizontalLayoutItems : function ( items , isInstant)
30510 if ( !items || !items.length || items.length < 3) {
30516 var eItems = items.slice(0, 3);
30518 items = items.slice(3, items.length);
30521 ['xs', 'xs', 'xs', 'wide'],
30522 ['xs', 'xs', 'wide'],
30523 ['xs', 'xs', 'sm'],
30524 ['xs', 'xs', 'xs'],
30530 ['sm', 'xs', 'xs'],
30534 ['wide', 'xs', 'xs', 'xs'],
30535 ['wide', 'xs', 'xs'],
30548 Roo.each(items, function(item, k){
30550 switch (item.size) {
30561 boxes.push([item]);
30585 var filterPattern = function(box, length)
30593 var pattern = box.slice(0, length);
30597 Roo.each(pattern, function(i){
30598 format.push(i.size);
30601 Roo.each(standard, function(s){
30603 if(String(s) != String(format)){
30612 if(!match && length == 1){
30617 filterPattern(box, length - 1);
30621 queue.push(pattern);
30623 box = box.slice(length, box.length);
30625 filterPattern(box, 4);
30631 Roo.each(boxes, function(box, k){
30637 if(box.length == 1){
30642 filterPattern(box, 4);
30649 var pos = this.el.getBox(true);
30653 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30655 var hit_end = false;
30657 Roo.each(queue, function(box){
30661 Roo.each(box, function(b){
30663 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30673 Roo.each(box, function(b){
30675 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30678 mx = Math.max(mx, b.x);
30682 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30686 Roo.each(box, function(b){
30688 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30702 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30705 /** Sets position of item in DOM
30706 * @param {Element} item
30707 * @param {Number} x - horizontal position
30708 * @param {Number} y - vertical position
30709 * @param {Boolean} isInstant - disables transitions
30711 _processVerticalLayoutQueue : function( queue, isInstant )
30713 var pos = this.el.getBox(true);
30718 for (var i = 0; i < this.cols; i++){
30722 Roo.each(queue, function(box, k){
30724 var col = k % this.cols;
30726 Roo.each(box, function(b,kk){
30728 b.el.position('absolute');
30730 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30731 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30733 if(b.size == 'md-left' || b.size == 'md-right'){
30734 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30735 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30738 b.el.setWidth(width);
30739 b.el.setHeight(height);
30741 b.el.select('iframe',true).setSize(width,height);
30745 for (var i = 0; i < this.cols; i++){
30747 if(maxY[i] < maxY[col]){
30752 col = Math.min(col, i);
30756 x = pos.x + col * (this.colWidth + this.padWidth);
30760 var positions = [];
30762 switch (box.length){
30764 positions = this.getVerticalOneBoxColPositions(x, y, box);
30767 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30770 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30773 positions = this.getVerticalFourBoxColPositions(x, y, box);
30779 Roo.each(box, function(b,kk){
30781 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30783 var sz = b.el.getSize();
30785 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30793 for (var i = 0; i < this.cols; i++){
30794 mY = Math.max(mY, maxY[i]);
30797 this.el.setHeight(mY - pos.y);
30801 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30803 // var pos = this.el.getBox(true);
30806 // var maxX = pos.right;
30808 // var maxHeight = 0;
30810 // Roo.each(items, function(item, k){
30814 // item.el.position('absolute');
30816 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30818 // item.el.setWidth(width);
30820 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30822 // item.el.setHeight(height);
30825 // item.el.setXY([x, y], isInstant ? false : true);
30827 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30830 // y = y + height + this.alternativePadWidth;
30832 // maxHeight = maxHeight + height + this.alternativePadWidth;
30836 // this.el.setHeight(maxHeight);
30840 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30842 var pos = this.el.getBox(true);
30847 var maxX = pos.right;
30849 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30851 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30853 Roo.each(queue, function(box, k){
30855 Roo.each(box, function(b, kk){
30857 b.el.position('absolute');
30859 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30860 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30862 if(b.size == 'md-left' || b.size == 'md-right'){
30863 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30864 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30867 b.el.setWidth(width);
30868 b.el.setHeight(height);
30876 var positions = [];
30878 switch (box.length){
30880 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30883 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30886 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30889 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30895 Roo.each(box, function(b,kk){
30897 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30899 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30907 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30909 Roo.each(eItems, function(b,k){
30911 b.size = (k == 0) ? 'sm' : 'xs';
30912 b.x = (k == 0) ? 2 : 1;
30913 b.y = (k == 0) ? 2 : 1;
30915 b.el.position('absolute');
30917 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30919 b.el.setWidth(width);
30921 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30923 b.el.setHeight(height);
30927 var positions = [];
30930 x : maxX - this.unitWidth * 2 - this.gutter,
30935 x : maxX - this.unitWidth,
30936 y : minY + (this.unitWidth + this.gutter) * 2
30940 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30944 Roo.each(eItems, function(b,k){
30946 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30952 getVerticalOneBoxColPositions : function(x, y, box)
30956 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30958 if(box[0].size == 'md-left'){
30962 if(box[0].size == 'md-right'){
30967 x : x + (this.unitWidth + this.gutter) * rand,
30974 getVerticalTwoBoxColPositions : function(x, y, box)
30978 if(box[0].size == 'xs'){
30982 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30986 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31000 x : x + (this.unitWidth + this.gutter) * 2,
31001 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31008 getVerticalThreeBoxColPositions : function(x, y, box)
31012 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31020 x : x + (this.unitWidth + this.gutter) * 1,
31025 x : x + (this.unitWidth + this.gutter) * 2,
31033 if(box[0].size == 'xs' && box[1].size == 'xs'){
31042 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31046 x : x + (this.unitWidth + this.gutter) * 1,
31060 x : x + (this.unitWidth + this.gutter) * 2,
31065 x : x + (this.unitWidth + this.gutter) * 2,
31066 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31073 getVerticalFourBoxColPositions : function(x, y, box)
31077 if(box[0].size == 'xs'){
31086 y : y + (this.unitHeight + this.gutter) * 1
31091 y : y + (this.unitHeight + this.gutter) * 2
31095 x : x + (this.unitWidth + this.gutter) * 1,
31109 x : x + (this.unitWidth + this.gutter) * 2,
31114 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31115 y : y + (this.unitHeight + this.gutter) * 1
31119 x : x + (this.unitWidth + this.gutter) * 2,
31120 y : y + (this.unitWidth + this.gutter) * 2
31127 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31131 if(box[0].size == 'md-left'){
31133 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31140 if(box[0].size == 'md-right'){
31142 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31143 y : minY + (this.unitWidth + this.gutter) * 1
31149 var rand = Math.floor(Math.random() * (4 - box[0].y));
31152 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31153 y : minY + (this.unitWidth + this.gutter) * rand
31160 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31164 if(box[0].size == 'xs'){
31167 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31172 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31173 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31181 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31186 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31187 y : minY + (this.unitWidth + this.gutter) * 2
31194 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31198 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31201 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31206 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31207 y : minY + (this.unitWidth + this.gutter) * 1
31211 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31212 y : minY + (this.unitWidth + this.gutter) * 2
31219 if(box[0].size == 'xs' && box[1].size == 'xs'){
31222 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31227 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31232 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31233 y : minY + (this.unitWidth + this.gutter) * 1
31241 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31246 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31247 y : minY + (this.unitWidth + this.gutter) * 2
31251 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31252 y : minY + (this.unitWidth + this.gutter) * 2
31259 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31263 if(box[0].size == 'xs'){
31266 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31271 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31276 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),
31281 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31282 y : minY + (this.unitWidth + this.gutter) * 1
31290 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31295 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31296 y : minY + (this.unitWidth + this.gutter) * 2
31300 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31301 y : minY + (this.unitWidth + this.gutter) * 2
31305 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),
31306 y : minY + (this.unitWidth + this.gutter) * 2
31314 * adds a Masonry Brick
31315 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31317 addItem : function(cfg)
31319 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31320 //this.register(cn);
31321 cn.parentId = this.id;
31322 cn.onRender(this.el, null);
31327 * register a Masonry Brick
31328 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31330 register : function(brick)
31332 this.bricks.push(brick);
31333 brick.masonryId = this.id;
31337 * clear all the Masonry Brick
31339 clearAll : function()
31342 //this.getChildContainer().dom.innerHTML = "";
31343 this.el.dom.innerHTML = '';
31346 getSelected : function()
31348 for (var i=0; i<this.bricks.length; i++) {
31349 Roo.log(this.bricks)[i];
31360 * http://masonry.desandro.com
31362 * The idea is to render all the bricks based on vertical width...
31364 * The original code extends 'outlayer' - we might need to use that....
31370 * @class Roo.bootstrap.LayoutMasonryAuto
31371 * @extends Roo.bootstrap.Component
31372 * Bootstrap Layout Masonry class
31375 * Create a new Element
31376 * @param {Object} config The config object
31379 Roo.bootstrap.LayoutMasonryAuto = function(config){
31380 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31383 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31386 * @cfg {Boolean} isFitWidth - resize the width..
31388 isFitWidth : false, // options..
31390 * @cfg {Boolean} isOriginLeft = left align?
31392 isOriginLeft : true,
31394 * @cfg {Boolean} isOriginTop = top align?
31396 isOriginTop : false,
31398 * @cfg {Boolean} isLayoutInstant = no animation?
31400 isLayoutInstant : false, // needed?
31402 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31404 isResizingContainer : true,
31406 * @cfg {Number} columnWidth width of the columns
31412 * @cfg {Number} maxCols maximum number of columns
31417 * @cfg {Number} padHeight padding below box..
31423 * @cfg {Boolean} isAutoInitial defalut true
31426 isAutoInitial : true,
31432 initialColumnWidth : 0,
31433 currentSize : null,
31435 colYs : null, // array.
31442 bricks: null, //CompositeElement
31443 cols : 0, // array?
31444 // element : null, // wrapped now this.el
31445 _isLayoutInited : null,
31448 getAutoCreate : function(){
31452 cls: 'blog-masonary-wrapper ' + this.cls,
31454 cls : 'mas-boxes masonary'
31461 getChildContainer: function( )
31463 if (this.boxesEl) {
31464 return this.boxesEl;
31467 this.boxesEl = this.el.select('.mas-boxes').first();
31469 return this.boxesEl;
31473 initEvents : function()
31477 if(this.isAutoInitial){
31478 Roo.log('hook children rendered');
31479 this.on('childrenrendered', function() {
31480 Roo.log('children rendered');
31487 initial : function()
31489 this.reloadItems();
31491 this.currentSize = this.el.getBox(true);
31493 /// was window resize... - let's see if this works..
31494 Roo.EventManager.onWindowResize(this.resize, this);
31496 if(!this.isAutoInitial){
31501 this.layout.defer(500,this);
31504 reloadItems: function()
31506 this.bricks = this.el.select('.masonry-brick', true);
31508 this.bricks.each(function(b) {
31509 //Roo.log(b.getSize());
31510 if (!b.attr('originalwidth')) {
31511 b.attr('originalwidth', b.getSize().width);
31516 Roo.log(this.bricks.elements.length);
31519 resize : function()
31522 var cs = this.el.getBox(true);
31524 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31525 Roo.log("no change in with or X");
31528 this.currentSize = cs;
31532 layout : function()
31535 this._resetLayout();
31536 //this._manageStamps();
31538 // don't animate first layout
31539 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31540 this.layoutItems( isInstant );
31542 // flag for initalized
31543 this._isLayoutInited = true;
31546 layoutItems : function( isInstant )
31548 //var items = this._getItemsForLayout( this.items );
31549 // original code supports filtering layout items.. we just ignore it..
31551 this._layoutItems( this.bricks , isInstant );
31553 this._postLayout();
31555 _layoutItems : function ( items , isInstant)
31557 //this.fireEvent( 'layout', this, items );
31560 if ( !items || !items.elements.length ) {
31561 // no items, emit event with empty array
31566 items.each(function(item) {
31567 Roo.log("layout item");
31569 // get x/y object from method
31570 var position = this._getItemLayoutPosition( item );
31572 position.item = item;
31573 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31574 queue.push( position );
31577 this._processLayoutQueue( queue );
31579 /** Sets position of item in DOM
31580 * @param {Element} item
31581 * @param {Number} x - horizontal position
31582 * @param {Number} y - vertical position
31583 * @param {Boolean} isInstant - disables transitions
31585 _processLayoutQueue : function( queue )
31587 for ( var i=0, len = queue.length; i < len; i++ ) {
31588 var obj = queue[i];
31589 obj.item.position('absolute');
31590 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31596 * Any logic you want to do after each layout,
31597 * i.e. size the container
31599 _postLayout : function()
31601 this.resizeContainer();
31604 resizeContainer : function()
31606 if ( !this.isResizingContainer ) {
31609 var size = this._getContainerSize();
31611 this.el.setSize(size.width,size.height);
31612 this.boxesEl.setSize(size.width,size.height);
31618 _resetLayout : function()
31620 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31621 this.colWidth = this.el.getWidth();
31622 //this.gutter = this.el.getWidth();
31624 this.measureColumns();
31630 this.colYs.push( 0 );
31636 measureColumns : function()
31638 this.getContainerWidth();
31639 // if columnWidth is 0, default to outerWidth of first item
31640 if ( !this.columnWidth ) {
31641 var firstItem = this.bricks.first();
31642 Roo.log(firstItem);
31643 this.columnWidth = this.containerWidth;
31644 if (firstItem && firstItem.attr('originalwidth') ) {
31645 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31647 // columnWidth fall back to item of first element
31648 Roo.log("set column width?");
31649 this.initialColumnWidth = this.columnWidth ;
31651 // if first elem has no width, default to size of container
31656 if (this.initialColumnWidth) {
31657 this.columnWidth = this.initialColumnWidth;
31662 // column width is fixed at the top - however if container width get's smaller we should
31665 // this bit calcs how man columns..
31667 var columnWidth = this.columnWidth += this.gutter;
31669 // calculate columns
31670 var containerWidth = this.containerWidth + this.gutter;
31672 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31673 // fix rounding errors, typically with gutters
31674 var excess = columnWidth - containerWidth % columnWidth;
31677 // if overshoot is less than a pixel, round up, otherwise floor it
31678 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31679 cols = Math[ mathMethod ]( cols );
31680 this.cols = Math.max( cols, 1 );
31681 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31683 // padding positioning..
31684 var totalColWidth = this.cols * this.columnWidth;
31685 var padavail = this.containerWidth - totalColWidth;
31686 // so for 2 columns - we need 3 'pads'
31688 var padNeeded = (1+this.cols) * this.padWidth;
31690 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31692 this.columnWidth += padExtra
31693 //this.padWidth = Math.floor(padavail / ( this.cols));
31695 // adjust colum width so that padding is fixed??
31697 // we have 3 columns ... total = width * 3
31698 // we have X left over... that should be used by
31700 //if (this.expandC) {
31708 getContainerWidth : function()
31710 /* // container is parent if fit width
31711 var container = this.isFitWidth ? this.element.parentNode : this.element;
31712 // check that this.size and size are there
31713 // IE8 triggers resize on body size change, so they might not be
31715 var size = getSize( container ); //FIXME
31716 this.containerWidth = size && size.innerWidth; //FIXME
31719 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31723 _getItemLayoutPosition : function( item ) // what is item?
31725 // we resize the item to our columnWidth..
31727 item.setWidth(this.columnWidth);
31728 item.autoBoxAdjust = false;
31730 var sz = item.getSize();
31732 // how many columns does this brick span
31733 var remainder = this.containerWidth % this.columnWidth;
31735 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31736 // round if off by 1 pixel, otherwise use ceil
31737 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31738 colSpan = Math.min( colSpan, this.cols );
31740 // normally this should be '1' as we dont' currently allow multi width columns..
31742 var colGroup = this._getColGroup( colSpan );
31743 // get the minimum Y value from the columns
31744 var minimumY = Math.min.apply( Math, colGroup );
31745 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31747 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31749 // position the brick
31751 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31752 y: this.currentSize.y + minimumY + this.padHeight
31756 // apply setHeight to necessary columns
31757 var setHeight = minimumY + sz.height + this.padHeight;
31758 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31760 var setSpan = this.cols + 1 - colGroup.length;
31761 for ( var i = 0; i < setSpan; i++ ) {
31762 this.colYs[ shortColIndex + i ] = setHeight ;
31769 * @param {Number} colSpan - number of columns the element spans
31770 * @returns {Array} colGroup
31772 _getColGroup : function( colSpan )
31774 if ( colSpan < 2 ) {
31775 // if brick spans only one column, use all the column Ys
31780 // how many different places could this brick fit horizontally
31781 var groupCount = this.cols + 1 - colSpan;
31782 // for each group potential horizontal position
31783 for ( var i = 0; i < groupCount; i++ ) {
31784 // make an array of colY values for that one group
31785 var groupColYs = this.colYs.slice( i, i + colSpan );
31786 // and get the max value of the array
31787 colGroup[i] = Math.max.apply( Math, groupColYs );
31792 _manageStamp : function( stamp )
31794 var stampSize = stamp.getSize();
31795 var offset = stamp.getBox();
31796 // get the columns that this stamp affects
31797 var firstX = this.isOriginLeft ? offset.x : offset.right;
31798 var lastX = firstX + stampSize.width;
31799 var firstCol = Math.floor( firstX / this.columnWidth );
31800 firstCol = Math.max( 0, firstCol );
31802 var lastCol = Math.floor( lastX / this.columnWidth );
31803 // lastCol should not go over if multiple of columnWidth #425
31804 lastCol -= lastX % this.columnWidth ? 0 : 1;
31805 lastCol = Math.min( this.cols - 1, lastCol );
31807 // set colYs to bottom of the stamp
31808 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31811 for ( var i = firstCol; i <= lastCol; i++ ) {
31812 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31817 _getContainerSize : function()
31819 this.maxY = Math.max.apply( Math, this.colYs );
31824 if ( this.isFitWidth ) {
31825 size.width = this._getContainerFitWidth();
31831 _getContainerFitWidth : function()
31833 var unusedCols = 0;
31834 // count unused columns
31837 if ( this.colYs[i] !== 0 ) {
31842 // fit container to columns that have been used
31843 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31846 needsResizeLayout : function()
31848 var previousWidth = this.containerWidth;
31849 this.getContainerWidth();
31850 return previousWidth !== this.containerWidth;
31865 * @class Roo.bootstrap.MasonryBrick
31866 * @extends Roo.bootstrap.Component
31867 * Bootstrap MasonryBrick class
31870 * Create a new MasonryBrick
31871 * @param {Object} config The config object
31874 Roo.bootstrap.MasonryBrick = function(config){
31875 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31881 * When a MasonryBrick is clcik
31882 * @param {Roo.bootstrap.MasonryBrick} this
31883 * @param {Roo.EventObject} e
31889 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31892 * @cfg {String} title
31896 * @cfg {String} html
31900 * @cfg {String} bgimage
31904 * @cfg {String} videourl
31908 * @cfg {String} cls
31912 * @cfg {String} href
31916 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
31921 * @cfg {String} placetitle (center|bottom)
31926 * @cfg {Boolean} isFitContainer defalut true
31928 isFitContainer : true,
31931 * @cfg {Boolean} preventDefault defalut false
31933 preventDefault : false,
31936 * @cfg {Boolean} inverse defalut false
31938 maskInverse : false,
31940 getAutoCreate : function()
31942 if(!this.isFitContainer){
31943 return this.getSplitAutoCreate();
31946 var cls = 'masonry-brick masonry-brick-full';
31948 if(this.href.length){
31949 cls += ' masonry-brick-link';
31952 if(this.bgimage.length){
31953 cls += ' masonry-brick-image';
31956 if(this.maskInverse){
31957 cls += ' mask-inverse';
31960 if(!this.html.length && !this.maskInverse){
31961 cls += ' enable-mask';
31965 cls += ' masonry-' + this.size + '-brick';
31968 if(this.placetitle.length){
31970 switch (this.placetitle) {
31972 cls += ' masonry-center-title';
31975 cls += ' masonry-bottom-title';
31982 if(!this.html.length && !this.bgimage.length){
31983 cls += ' masonry-center-title';
31986 if(!this.html.length && this.bgimage.length){
31987 cls += ' masonry-bottom-title';
31992 cls += ' ' + this.cls;
31996 tag: (this.href.length) ? 'a' : 'div',
32001 cls: 'masonry-brick-paragraph',
32007 if(this.href.length){
32008 cfg.href = this.href;
32011 var cn = cfg.cn[0].cn;
32013 if(this.title.length){
32016 cls: 'masonry-brick-title',
32021 if(this.html.length){
32024 cls: 'masonry-brick-text',
32028 if (!this.title.length && !this.html.length) {
32029 cfg.cn[0].cls += ' hide';
32032 if(this.bgimage.length){
32035 cls: 'masonry-brick-image-view',
32040 if(this.videourl.length){
32041 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32042 // youtube support only?
32045 cls: 'masonry-brick-image-view',
32048 allowfullscreen : true
32056 cls: 'masonry-brick-mask'
32063 getSplitAutoCreate : function()
32065 var cls = 'masonry-brick masonry-brick-split';
32067 if(this.href.length){
32068 cls += ' masonry-brick-link';
32071 if(this.bgimage.length){
32072 cls += ' masonry-brick-image';
32076 cls += ' masonry-' + this.size + '-brick';
32079 switch (this.placetitle) {
32081 cls += ' masonry-center-title';
32084 cls += ' masonry-bottom-title';
32087 if(!this.bgimage.length){
32088 cls += ' masonry-center-title';
32091 if(this.bgimage.length){
32092 cls += ' masonry-bottom-title';
32098 cls += ' ' + this.cls;
32102 tag: (this.href.length) ? 'a' : 'div',
32107 cls: 'masonry-brick-split-head',
32111 cls: 'masonry-brick-paragraph',
32118 cls: 'masonry-brick-split-body',
32124 if(this.href.length){
32125 cfg.href = this.href;
32128 if(this.title.length){
32129 cfg.cn[0].cn[0].cn.push({
32131 cls: 'masonry-brick-title',
32136 if(this.html.length){
32137 cfg.cn[1].cn.push({
32139 cls: 'masonry-brick-text',
32144 if(this.bgimage.length){
32145 cfg.cn[0].cn.push({
32147 cls: 'masonry-brick-image-view',
32152 if(this.videourl.length){
32153 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32154 // youtube support only?
32155 cfg.cn[0].cn.cn.push({
32157 cls: 'masonry-brick-image-view',
32160 allowfullscreen : true
32167 initEvents: function()
32169 switch (this.size) {
32202 this.el.on('touchstart', this.onTouchStart, this);
32203 this.el.on('touchmove', this.onTouchMove, this);
32204 this.el.on('touchend', this.onTouchEnd, this);
32205 this.el.on('contextmenu', this.onContextMenu, this);
32207 this.el.on('mouseenter' ,this.enter, this);
32208 this.el.on('mouseleave', this.leave, this);
32209 this.el.on('click', this.onClick, this);
32212 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32213 this.parent().bricks.push(this);
32218 onClick: function(e, el)
32220 var time = this.endTimer - this.startTimer;
32224 e.preventDefault();
32229 if(!this.preventDefault){
32233 e.preventDefault();
32234 this.fireEvent('click', this);
32237 enter: function(e, el)
32239 e.preventDefault();
32241 if(!this.isFitContainer || this.maskInverse){
32245 if(this.bgimage.length && this.html.length){
32246 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32250 leave: function(e, el)
32252 e.preventDefault();
32254 if(!this.isFitContainer || this.maskInverse){
32258 if(this.bgimage.length && this.html.length){
32259 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32263 onTouchStart: function(e, el)
32265 // e.preventDefault();
32267 this.touchmoved = false;
32269 if(!this.isFitContainer){
32273 if(!this.bgimage.length || !this.html.length){
32277 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32279 this.timer = new Date().getTime();
32283 onTouchMove: function(e, el)
32285 this.touchmoved = true;
32288 onContextMenu : function(e,el)
32290 e.preventDefault();
32291 e.stopPropagation();
32295 onTouchEnd: function(e, el)
32297 // e.preventDefault();
32299 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32306 if(!this.bgimage.length || !this.html.length){
32308 if(this.href.length){
32309 window.location.href = this.href;
32315 if(!this.isFitContainer){
32319 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32321 window.location.href = this.href;
32336 * @class Roo.bootstrap.Brick
32337 * @extends Roo.bootstrap.Component
32338 * Bootstrap Brick class
32341 * Create a new Brick
32342 * @param {Object} config The config object
32345 Roo.bootstrap.Brick = function(config){
32346 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32352 * When a Brick is click
32353 * @param {Roo.bootstrap.Brick} this
32354 * @param {Roo.EventObject} e
32360 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32363 * @cfg {String} title
32367 * @cfg {String} html
32371 * @cfg {String} bgimage
32375 * @cfg {String} cls
32379 * @cfg {String} href
32383 * @cfg {String} video
32387 * @cfg {Boolean} square
32391 getAutoCreate : function()
32393 var cls = 'roo-brick';
32395 if(this.href.length){
32396 cls += ' roo-brick-link';
32399 if(this.bgimage.length){
32400 cls += ' roo-brick-image';
32403 if(!this.html.length && !this.bgimage.length){
32404 cls += ' roo-brick-center-title';
32407 if(!this.html.length && this.bgimage.length){
32408 cls += ' roo-brick-bottom-title';
32412 cls += ' ' + this.cls;
32416 tag: (this.href.length) ? 'a' : 'div',
32421 cls: 'roo-brick-paragraph',
32427 if(this.href.length){
32428 cfg.href = this.href;
32431 var cn = cfg.cn[0].cn;
32433 if(this.title.length){
32436 cls: 'roo-brick-title',
32441 if(this.html.length){
32444 cls: 'roo-brick-text',
32451 if(this.bgimage.length){
32454 cls: 'roo-brick-image-view',
32462 initEvents: function()
32464 if(this.title.length || this.html.length){
32465 this.el.on('mouseenter' ,this.enter, this);
32466 this.el.on('mouseleave', this.leave, this);
32470 Roo.EventManager.onWindowResize(this.resize, this);
32475 resize : function()
32477 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32479 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32481 if(this.bgimage.length){
32482 var image = this.el.select('.roo-brick-image-view', true).first();
32483 image.setWidth(paragraph.getWidth());
32484 image.setHeight(paragraph.getWidth());
32486 this.el.setHeight(paragraph.getWidth());
32492 enter: function(e, el)
32494 e.preventDefault();
32496 if(this.bgimage.length){
32497 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32498 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32502 leave: function(e, el)
32504 e.preventDefault();
32506 if(this.bgimage.length){
32507 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32508 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32524 * @class Roo.bootstrap.NumberField
32525 * @extends Roo.bootstrap.Input
32526 * Bootstrap NumberField class
32532 * Create a new NumberField
32533 * @param {Object} config The config object
32536 Roo.bootstrap.NumberField = function(config){
32537 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32540 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32543 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32545 allowDecimals : true,
32547 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32549 decimalSeparator : ".",
32551 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32553 decimalPrecision : 2,
32555 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32557 allowNegative : true,
32559 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32561 minValue : Number.NEGATIVE_INFINITY,
32563 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32565 maxValue : Number.MAX_VALUE,
32567 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32569 minText : "The minimum value for this field is {0}",
32571 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32573 maxText : "The maximum value for this field is {0}",
32575 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32576 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32578 nanText : "{0} is not a valid number",
32580 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32585 initEvents : function()
32587 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32589 var allowed = "0123456789";
32591 if(this.allowDecimals){
32592 allowed += this.decimalSeparator;
32595 if(this.allowNegative){
32599 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32601 var keyPress = function(e){
32603 var k = e.getKey();
32605 var c = e.getCharCode();
32608 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32609 allowed.indexOf(String.fromCharCode(c)) === -1
32615 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32619 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32624 this.el.on("keypress", keyPress, this);
32627 validateValue : function(value)
32630 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32634 var num = this.parseValue(value);
32637 this.markInvalid(String.format(this.nanText, value));
32641 if(num < this.minValue){
32642 this.markInvalid(String.format(this.minText, this.minValue));
32646 if(num > this.maxValue){
32647 this.markInvalid(String.format(this.maxText, this.maxValue));
32654 getValue : function()
32656 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32659 parseValue : function(value)
32661 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32662 return isNaN(value) ? '' : value;
32665 fixPrecision : function(value)
32667 var nan = isNaN(value);
32669 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32670 return nan ? '' : value;
32672 return parseFloat(value).toFixed(this.decimalPrecision);
32675 setValue : function(v)
32677 v = this.fixPrecision(v);
32678 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32681 decimalPrecisionFcn : function(v)
32683 return Math.floor(v);
32686 beforeBlur : function()
32692 var v = this.parseValue(this.getRawValue());
32707 * @class Roo.bootstrap.DocumentSlider
32708 * @extends Roo.bootstrap.Component
32709 * Bootstrap DocumentSlider class
32712 * Create a new DocumentViewer
32713 * @param {Object} config The config object
32716 Roo.bootstrap.DocumentSlider = function(config){
32717 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32724 * Fire after initEvent
32725 * @param {Roo.bootstrap.DocumentSlider} this
32730 * Fire after update
32731 * @param {Roo.bootstrap.DocumentSlider} this
32737 * @param {Roo.bootstrap.DocumentSlider} this
32743 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32749 getAutoCreate : function()
32753 cls : 'roo-document-slider',
32757 cls : 'roo-document-slider-header',
32761 cls : 'roo-document-slider-header-title'
32767 cls : 'roo-document-slider-body',
32771 cls : 'roo-document-slider-prev',
32775 cls : 'fa fa-chevron-left'
32781 cls : 'roo-document-slider-thumb',
32785 cls : 'roo-document-slider-image'
32791 cls : 'roo-document-slider-next',
32795 cls : 'fa fa-chevron-right'
32807 initEvents : function()
32809 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32810 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32812 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32813 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32815 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32816 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32818 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32819 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32821 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32822 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32824 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32825 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32827 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32828 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32830 this.thumbEl.on('click', this.onClick, this);
32832 this.prevIndicator.on('click', this.prev, this);
32834 this.nextIndicator.on('click', this.next, this);
32838 initial : function()
32840 if(this.files.length){
32841 this.indicator = 1;
32845 this.fireEvent('initial', this);
32848 update : function()
32850 this.imageEl.attr('src', this.files[this.indicator - 1]);
32852 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32854 this.prevIndicator.show();
32856 if(this.indicator == 1){
32857 this.prevIndicator.hide();
32860 this.nextIndicator.show();
32862 if(this.indicator == this.files.length){
32863 this.nextIndicator.hide();
32866 this.thumbEl.scrollTo('top');
32868 this.fireEvent('update', this);
32871 onClick : function(e)
32873 e.preventDefault();
32875 this.fireEvent('click', this);
32880 e.preventDefault();
32882 this.indicator = Math.max(1, this.indicator - 1);
32889 e.preventDefault();
32891 this.indicator = Math.min(this.files.length, this.indicator + 1);
32905 * @class Roo.bootstrap.RadioSet
32906 * @extends Roo.bootstrap.Input
32907 * Bootstrap RadioSet class
32908 * @cfg {String} indicatorpos (left|right) default left
32909 * @cfg {Boolean} inline (true|false) inline the element (default true)
32910 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32912 * Create a new RadioSet
32913 * @param {Object} config The config object
32916 Roo.bootstrap.RadioSet = function(config){
32918 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32922 Roo.bootstrap.RadioSet.register(this);
32927 * Fires when the element is checked or unchecked.
32928 * @param {Roo.bootstrap.RadioSet} this This radio
32929 * @param {Roo.bootstrap.Radio} item The checked item
32936 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32944 indicatorpos : 'left',
32946 getAutoCreate : function()
32950 cls : 'roo-radio-set-label',
32954 html : this.fieldLabel
32959 if(this.indicatorpos == 'left'){
32962 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32963 tooltip : 'This field is required'
32968 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32969 tooltip : 'This field is required'
32975 cls : 'roo-radio-set-items'
32978 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32980 if (align === 'left' && this.fieldLabel.length) {
32983 cls : "roo-radio-set-right",
32989 if(this.labelWidth > 12){
32990 label.style = "width: " + this.labelWidth + 'px';
32993 if(this.labelWidth < 13 && this.labelmd == 0){
32994 this.labelmd = this.labelWidth;
32997 if(this.labellg > 0){
32998 label.cls += ' col-lg-' + this.labellg;
32999 items.cls += ' col-lg-' + (12 - this.labellg);
33002 if(this.labelmd > 0){
33003 label.cls += ' col-md-' + this.labelmd;
33004 items.cls += ' col-md-' + (12 - this.labelmd);
33007 if(this.labelsm > 0){
33008 label.cls += ' col-sm-' + this.labelsm;
33009 items.cls += ' col-sm-' + (12 - this.labelsm);
33012 if(this.labelxs > 0){
33013 label.cls += ' col-xs-' + this.labelxs;
33014 items.cls += ' col-xs-' + (12 - this.labelxs);
33020 cls : 'roo-radio-set',
33024 cls : 'roo-radio-set-input',
33027 value : this.value ? this.value : ''
33034 if(this.weight.length){
33035 cfg.cls += ' roo-radio-' + this.weight;
33039 cfg.cls += ' roo-radio-set-inline';
33046 initEvents : function()
33048 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33049 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33051 if(!this.fieldLabel.length){
33052 this.labelEl.hide();
33055 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33056 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33058 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
33059 this.indicatorEl().hide();
33061 this.originalValue = this.getValue();
33065 inputEl: function ()
33067 return this.el.select('.roo-radio-set-input', true).first();
33070 getChildContainer : function()
33072 return this.itemsEl;
33075 register : function(item)
33077 this.radioes.push(item);
33081 validate : function()
33085 Roo.each(this.radioes, function(i){
33094 if(this.allowBlank) {
33098 if(this.disabled || valid){
33103 this.markInvalid();
33108 markValid : function()
33110 if(this.labelEl.isVisible(true)){
33111 this.indicatorEl().hide();
33114 this.el.removeClass([this.invalidClass, this.validClass]);
33115 this.el.addClass(this.validClass);
33117 this.fireEvent('valid', this);
33120 markInvalid : function(msg)
33122 if(this.allowBlank || this.disabled){
33126 if(this.labelEl.isVisible(true)){
33127 this.indicatorEl().show();
33130 this.el.removeClass([this.invalidClass, this.validClass]);
33131 this.el.addClass(this.invalidClass);
33133 this.fireEvent('invalid', this, msg);
33137 setValue : function(v, suppressEvent)
33139 Roo.each(this.radioes, function(i){
33142 i.el.removeClass('checked');
33144 if(i.value === v || i.value.toString() === v.toString()){
33146 i.el.addClass('checked');
33148 if(suppressEvent !== true){
33149 this.fireEvent('check', this, i);
33155 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
33159 clearInvalid : function(){
33161 if(!this.el || this.preventMark){
33165 if(this.labelEl.isVisible(true)){
33166 this.indicatorEl().hide();
33169 this.el.removeClass([this.invalidClass]);
33171 this.fireEvent('valid', this);
33176 Roo.apply(Roo.bootstrap.RadioSet, {
33180 register : function(set)
33182 this.groups[set.name] = set;
33185 get: function(name)
33187 if (typeof(this.groups[name]) == 'undefined') {
33191 return this.groups[name] ;
33197 * Ext JS Library 1.1.1
33198 * Copyright(c) 2006-2007, Ext JS, LLC.
33200 * Originally Released Under LGPL - original licence link has changed is not relivant.
33203 * <script type="text/javascript">
33208 * @class Roo.bootstrap.SplitBar
33209 * @extends Roo.util.Observable
33210 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33214 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33215 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33216 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33217 split.minSize = 100;
33218 split.maxSize = 600;
33219 split.animate = true;
33220 split.on('moved', splitterMoved);
33223 * Create a new SplitBar
33224 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33225 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33226 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33227 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33228 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33229 position of the SplitBar).
33231 Roo.bootstrap.SplitBar = function(cfg){
33236 // dragElement : elm
33237 // resizingElement: el,
33239 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33240 // placement : Roo.bootstrap.SplitBar.LEFT ,
33241 // existingProxy ???
33244 this.el = Roo.get(cfg.dragElement, true);
33245 this.el.dom.unselectable = "on";
33247 this.resizingEl = Roo.get(cfg.resizingElement, true);
33251 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33252 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33255 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33258 * The minimum size of the resizing element. (Defaults to 0)
33264 * The maximum size of the resizing element. (Defaults to 2000)
33267 this.maxSize = 2000;
33270 * Whether to animate the transition to the new size
33273 this.animate = false;
33276 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33279 this.useShim = false;
33284 if(!cfg.existingProxy){
33286 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33288 this.proxy = Roo.get(cfg.existingProxy).dom;
33291 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33294 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33297 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33300 this.dragSpecs = {};
33303 * @private The adapter to use to positon and resize elements
33305 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33306 this.adapter.init(this);
33308 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33310 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33311 this.el.addClass("roo-splitbar-h");
33314 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33315 this.el.addClass("roo-splitbar-v");
33321 * Fires when the splitter is moved (alias for {@link #event-moved})
33322 * @param {Roo.bootstrap.SplitBar} this
33323 * @param {Number} newSize the new width or height
33328 * Fires when the splitter is moved
33329 * @param {Roo.bootstrap.SplitBar} this
33330 * @param {Number} newSize the new width or height
33334 * @event beforeresize
33335 * Fires before the splitter is dragged
33336 * @param {Roo.bootstrap.SplitBar} this
33338 "beforeresize" : true,
33340 "beforeapply" : true
33343 Roo.util.Observable.call(this);
33346 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33347 onStartProxyDrag : function(x, y){
33348 this.fireEvent("beforeresize", this);
33350 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33352 o.enableDisplayMode("block");
33353 // all splitbars share the same overlay
33354 Roo.bootstrap.SplitBar.prototype.overlay = o;
33356 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33357 this.overlay.show();
33358 Roo.get(this.proxy).setDisplayed("block");
33359 var size = this.adapter.getElementSize(this);
33360 this.activeMinSize = this.getMinimumSize();;
33361 this.activeMaxSize = this.getMaximumSize();;
33362 var c1 = size - this.activeMinSize;
33363 var c2 = Math.max(this.activeMaxSize - size, 0);
33364 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33365 this.dd.resetConstraints();
33366 this.dd.setXConstraint(
33367 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33368 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33370 this.dd.setYConstraint(0, 0);
33372 this.dd.resetConstraints();
33373 this.dd.setXConstraint(0, 0);
33374 this.dd.setYConstraint(
33375 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33376 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33379 this.dragSpecs.startSize = size;
33380 this.dragSpecs.startPoint = [x, y];
33381 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33385 * @private Called after the drag operation by the DDProxy
33387 onEndProxyDrag : function(e){
33388 Roo.get(this.proxy).setDisplayed(false);
33389 var endPoint = Roo.lib.Event.getXY(e);
33391 this.overlay.hide();
33394 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33395 newSize = this.dragSpecs.startSize +
33396 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33397 endPoint[0] - this.dragSpecs.startPoint[0] :
33398 this.dragSpecs.startPoint[0] - endPoint[0]
33401 newSize = this.dragSpecs.startSize +
33402 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33403 endPoint[1] - this.dragSpecs.startPoint[1] :
33404 this.dragSpecs.startPoint[1] - endPoint[1]
33407 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33408 if(newSize != this.dragSpecs.startSize){
33409 if(this.fireEvent('beforeapply', this, newSize) !== false){
33410 this.adapter.setElementSize(this, newSize);
33411 this.fireEvent("moved", this, newSize);
33412 this.fireEvent("resize", this, newSize);
33418 * Get the adapter this SplitBar uses
33419 * @return The adapter object
33421 getAdapter : function(){
33422 return this.adapter;
33426 * Set the adapter this SplitBar uses
33427 * @param {Object} adapter A SplitBar adapter object
33429 setAdapter : function(adapter){
33430 this.adapter = adapter;
33431 this.adapter.init(this);
33435 * Gets the minimum size for the resizing element
33436 * @return {Number} The minimum size
33438 getMinimumSize : function(){
33439 return this.minSize;
33443 * Sets the minimum size for the resizing element
33444 * @param {Number} minSize The minimum size
33446 setMinimumSize : function(minSize){
33447 this.minSize = minSize;
33451 * Gets the maximum size for the resizing element
33452 * @return {Number} The maximum size
33454 getMaximumSize : function(){
33455 return this.maxSize;
33459 * Sets the maximum size for the resizing element
33460 * @param {Number} maxSize The maximum size
33462 setMaximumSize : function(maxSize){
33463 this.maxSize = maxSize;
33467 * Sets the initialize size for the resizing element
33468 * @param {Number} size The initial size
33470 setCurrentSize : function(size){
33471 var oldAnimate = this.animate;
33472 this.animate = false;
33473 this.adapter.setElementSize(this, size);
33474 this.animate = oldAnimate;
33478 * Destroy this splitbar.
33479 * @param {Boolean} removeEl True to remove the element
33481 destroy : function(removeEl){
33483 this.shim.remove();
33486 this.proxy.parentNode.removeChild(this.proxy);
33494 * @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.
33496 Roo.bootstrap.SplitBar.createProxy = function(dir){
33497 var proxy = new Roo.Element(document.createElement("div"));
33498 proxy.unselectable();
33499 var cls = 'roo-splitbar-proxy';
33500 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33501 document.body.appendChild(proxy.dom);
33506 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33507 * Default Adapter. It assumes the splitter and resizing element are not positioned
33508 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33510 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33513 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33514 // do nothing for now
33515 init : function(s){
33519 * Called before drag operations to get the current size of the resizing element.
33520 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33522 getElementSize : function(s){
33523 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33524 return s.resizingEl.getWidth();
33526 return s.resizingEl.getHeight();
33531 * Called after drag operations to set the size of the resizing element.
33532 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33533 * @param {Number} newSize The new size to set
33534 * @param {Function} onComplete A function to be invoked when resizing is complete
33536 setElementSize : function(s, newSize, onComplete){
33537 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33539 s.resizingEl.setWidth(newSize);
33541 onComplete(s, newSize);
33544 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33549 s.resizingEl.setHeight(newSize);
33551 onComplete(s, newSize);
33554 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33561 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33562 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33563 * Adapter that moves the splitter element to align with the resized sizing element.
33564 * Used with an absolute positioned SplitBar.
33565 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33566 * document.body, make sure you assign an id to the body element.
33568 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33569 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33570 this.container = Roo.get(container);
33573 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33574 init : function(s){
33575 this.basic.init(s);
33578 getElementSize : function(s){
33579 return this.basic.getElementSize(s);
33582 setElementSize : function(s, newSize, onComplete){
33583 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33586 moveSplitter : function(s){
33587 var yes = Roo.bootstrap.SplitBar;
33588 switch(s.placement){
33590 s.el.setX(s.resizingEl.getRight());
33593 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33596 s.el.setY(s.resizingEl.getBottom());
33599 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33606 * Orientation constant - Create a vertical SplitBar
33610 Roo.bootstrap.SplitBar.VERTICAL = 1;
33613 * Orientation constant - Create a horizontal SplitBar
33617 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33620 * Placement constant - The resizing element is to the left of the splitter element
33624 Roo.bootstrap.SplitBar.LEFT = 1;
33627 * Placement constant - The resizing element is to the right of the splitter element
33631 Roo.bootstrap.SplitBar.RIGHT = 2;
33634 * Placement constant - The resizing element is positioned above the splitter element
33638 Roo.bootstrap.SplitBar.TOP = 3;
33641 * Placement constant - The resizing element is positioned under splitter element
33645 Roo.bootstrap.SplitBar.BOTTOM = 4;
33646 Roo.namespace("Roo.bootstrap.layout");/*
33648 * Ext JS Library 1.1.1
33649 * Copyright(c) 2006-2007, Ext JS, LLC.
33651 * Originally Released Under LGPL - original licence link has changed is not relivant.
33654 * <script type="text/javascript">
33658 * @class Roo.bootstrap.layout.Manager
33659 * @extends Roo.bootstrap.Component
33660 * Base class for layout managers.
33662 Roo.bootstrap.layout.Manager = function(config)
33664 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33670 /** false to disable window resize monitoring @type Boolean */
33671 this.monitorWindowResize = true;
33676 * Fires when a layout is performed.
33677 * @param {Roo.LayoutManager} this
33681 * @event regionresized
33682 * Fires when the user resizes a region.
33683 * @param {Roo.LayoutRegion} region The resized region
33684 * @param {Number} newSize The new size (width for east/west, height for north/south)
33686 "regionresized" : true,
33688 * @event regioncollapsed
33689 * Fires when a region is collapsed.
33690 * @param {Roo.LayoutRegion} region The collapsed region
33692 "regioncollapsed" : true,
33694 * @event regionexpanded
33695 * Fires when a region is expanded.
33696 * @param {Roo.LayoutRegion} region The expanded region
33698 "regionexpanded" : true
33700 this.updating = false;
33703 this.el = Roo.get(config.el);
33709 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33714 monitorWindowResize : true,
33720 onRender : function(ct, position)
33723 this.el = Roo.get(ct);
33726 //this.fireEvent('render',this);
33730 initEvents: function()
33734 // ie scrollbar fix
33735 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33736 document.body.scroll = "no";
33737 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33738 this.el.position('relative');
33740 this.id = this.el.id;
33741 this.el.addClass("roo-layout-container");
33742 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33743 if(this.el.dom != document.body ) {
33744 this.el.on('resize', this.layout,this);
33745 this.el.on('show', this.layout,this);
33751 * Returns true if this layout is currently being updated
33752 * @return {Boolean}
33754 isUpdating : function(){
33755 return this.updating;
33759 * Suspend the LayoutManager from doing auto-layouts while
33760 * making multiple add or remove calls
33762 beginUpdate : function(){
33763 this.updating = true;
33767 * Restore auto-layouts and optionally disable the manager from performing a layout
33768 * @param {Boolean} noLayout true to disable a layout update
33770 endUpdate : function(noLayout){
33771 this.updating = false;
33777 layout: function(){
33781 onRegionResized : function(region, newSize){
33782 this.fireEvent("regionresized", region, newSize);
33786 onRegionCollapsed : function(region){
33787 this.fireEvent("regioncollapsed", region);
33790 onRegionExpanded : function(region){
33791 this.fireEvent("regionexpanded", region);
33795 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33796 * performs box-model adjustments.
33797 * @return {Object} The size as an object {width: (the width), height: (the height)}
33799 getViewSize : function()
33802 if(this.el.dom != document.body){
33803 size = this.el.getSize();
33805 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33807 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33808 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33813 * Returns the Element this layout is bound to.
33814 * @return {Roo.Element}
33816 getEl : function(){
33821 * Returns the specified region.
33822 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33823 * @return {Roo.LayoutRegion}
33825 getRegion : function(target){
33826 return this.regions[target.toLowerCase()];
33829 onWindowResize : function(){
33830 if(this.monitorWindowResize){
33837 * Ext JS Library 1.1.1
33838 * Copyright(c) 2006-2007, Ext JS, LLC.
33840 * Originally Released Under LGPL - original licence link has changed is not relivant.
33843 * <script type="text/javascript">
33846 * @class Roo.bootstrap.layout.Border
33847 * @extends Roo.bootstrap.layout.Manager
33848 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33849 * please see: examples/bootstrap/nested.html<br><br>
33851 <b>The container the layout is rendered into can be either the body element or any other element.
33852 If it is not the body element, the container needs to either be an absolute positioned element,
33853 or you will need to add "position:relative" to the css of the container. You will also need to specify
33854 the container size if it is not the body element.</b>
33857 * Create a new Border
33858 * @param {Object} config Configuration options
33860 Roo.bootstrap.layout.Border = function(config){
33861 config = config || {};
33862 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33866 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33867 if(config[region]){
33868 config[region].region = region;
33869 this.addRegion(config[region]);
33875 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33877 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33879 * Creates and adds a new region if it doesn't already exist.
33880 * @param {String} target The target region key (north, south, east, west or center).
33881 * @param {Object} config The regions config object
33882 * @return {BorderLayoutRegion} The new region
33884 addRegion : function(config)
33886 if(!this.regions[config.region]){
33887 var r = this.factory(config);
33888 this.bindRegion(r);
33890 return this.regions[config.region];
33894 bindRegion : function(r){
33895 this.regions[r.config.region] = r;
33897 r.on("visibilitychange", this.layout, this);
33898 r.on("paneladded", this.layout, this);
33899 r.on("panelremoved", this.layout, this);
33900 r.on("invalidated", this.layout, this);
33901 r.on("resized", this.onRegionResized, this);
33902 r.on("collapsed", this.onRegionCollapsed, this);
33903 r.on("expanded", this.onRegionExpanded, this);
33907 * Performs a layout update.
33909 layout : function()
33911 if(this.updating) {
33915 // render all the rebions if they have not been done alreayd?
33916 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33917 if(this.regions[region] && !this.regions[region].bodyEl){
33918 this.regions[region].onRender(this.el)
33922 var size = this.getViewSize();
33923 var w = size.width;
33924 var h = size.height;
33929 //var x = 0, y = 0;
33931 var rs = this.regions;
33932 var north = rs["north"];
33933 var south = rs["south"];
33934 var west = rs["west"];
33935 var east = rs["east"];
33936 var center = rs["center"];
33937 //if(this.hideOnLayout){ // not supported anymore
33938 //c.el.setStyle("display", "none");
33940 if(north && north.isVisible()){
33941 var b = north.getBox();
33942 var m = north.getMargins();
33943 b.width = w - (m.left+m.right);
33946 centerY = b.height + b.y + m.bottom;
33947 centerH -= centerY;
33948 north.updateBox(this.safeBox(b));
33950 if(south && south.isVisible()){
33951 var b = south.getBox();
33952 var m = south.getMargins();
33953 b.width = w - (m.left+m.right);
33955 var totalHeight = (b.height + m.top + m.bottom);
33956 b.y = h - totalHeight + m.top;
33957 centerH -= totalHeight;
33958 south.updateBox(this.safeBox(b));
33960 if(west && west.isVisible()){
33961 var b = west.getBox();
33962 var m = west.getMargins();
33963 b.height = centerH - (m.top+m.bottom);
33965 b.y = centerY + m.top;
33966 var totalWidth = (b.width + m.left + m.right);
33967 centerX += totalWidth;
33968 centerW -= totalWidth;
33969 west.updateBox(this.safeBox(b));
33971 if(east && east.isVisible()){
33972 var b = east.getBox();
33973 var m = east.getMargins();
33974 b.height = centerH - (m.top+m.bottom);
33975 var totalWidth = (b.width + m.left + m.right);
33976 b.x = w - totalWidth + m.left;
33977 b.y = centerY + m.top;
33978 centerW -= totalWidth;
33979 east.updateBox(this.safeBox(b));
33982 var m = center.getMargins();
33984 x: centerX + m.left,
33985 y: centerY + m.top,
33986 width: centerW - (m.left+m.right),
33987 height: centerH - (m.top+m.bottom)
33989 //if(this.hideOnLayout){
33990 //center.el.setStyle("display", "block");
33992 center.updateBox(this.safeBox(centerBox));
33995 this.fireEvent("layout", this);
33999 safeBox : function(box){
34000 box.width = Math.max(0, box.width);
34001 box.height = Math.max(0, box.height);
34006 * Adds a ContentPanel (or subclass) to this layout.
34007 * @param {String} target The target region key (north, south, east, west or center).
34008 * @param {Roo.ContentPanel} panel The panel to add
34009 * @return {Roo.ContentPanel} The added panel
34011 add : function(target, panel){
34013 target = target.toLowerCase();
34014 return this.regions[target].add(panel);
34018 * Remove a ContentPanel (or subclass) to this layout.
34019 * @param {String} target The target region key (north, south, east, west or center).
34020 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34021 * @return {Roo.ContentPanel} The removed panel
34023 remove : function(target, panel){
34024 target = target.toLowerCase();
34025 return this.regions[target].remove(panel);
34029 * Searches all regions for a panel with the specified id
34030 * @param {String} panelId
34031 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34033 findPanel : function(panelId){
34034 var rs = this.regions;
34035 for(var target in rs){
34036 if(typeof rs[target] != "function"){
34037 var p = rs[target].getPanel(panelId);
34047 * Searches all regions for a panel with the specified id and activates (shows) it.
34048 * @param {String/ContentPanel} panelId The panels id or the panel itself
34049 * @return {Roo.ContentPanel} The shown panel or null
34051 showPanel : function(panelId) {
34052 var rs = this.regions;
34053 for(var target in rs){
34054 var r = rs[target];
34055 if(typeof r != "function"){
34056 if(r.hasPanel(panelId)){
34057 return r.showPanel(panelId);
34065 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34066 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34069 restoreState : function(provider){
34071 provider = Roo.state.Manager;
34073 var sm = new Roo.LayoutStateManager();
34074 sm.init(this, provider);
34080 * Adds a xtype elements to the layout.
34084 xtype : 'ContentPanel',
34091 xtype : 'NestedLayoutPanel',
34097 items : [ ... list of content panels or nested layout panels.. ]
34101 * @param {Object} cfg Xtype definition of item to add.
34103 addxtype : function(cfg)
34105 // basically accepts a pannel...
34106 // can accept a layout region..!?!?
34107 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34110 // theory? children can only be panels??
34112 //if (!cfg.xtype.match(/Panel$/)) {
34117 if (typeof(cfg.region) == 'undefined') {
34118 Roo.log("Failed to add Panel, region was not set");
34122 var region = cfg.region;
34128 xitems = cfg.items;
34135 case 'Content': // ContentPanel (el, cfg)
34136 case 'Scroll': // ContentPanel (el, cfg)
34138 cfg.autoCreate = true;
34139 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34141 // var el = this.el.createChild();
34142 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34145 this.add(region, ret);
34149 case 'TreePanel': // our new panel!
34150 cfg.el = this.el.createChild();
34151 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34152 this.add(region, ret);
34157 // create a new Layout (which is a Border Layout...
34159 var clayout = cfg.layout;
34160 clayout.el = this.el.createChild();
34161 clayout.items = clayout.items || [];
34165 // replace this exitems with the clayout ones..
34166 xitems = clayout.items;
34168 // force background off if it's in center...
34169 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34170 cfg.background = false;
34172 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34175 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34176 //console.log('adding nested layout panel ' + cfg.toSource());
34177 this.add(region, ret);
34178 nb = {}; /// find first...
34183 // needs grid and region
34185 //var el = this.getRegion(region).el.createChild();
34187 *var el = this.el.createChild();
34188 // create the grid first...
34189 cfg.grid.container = el;
34190 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34193 if (region == 'center' && this.active ) {
34194 cfg.background = false;
34197 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34199 this.add(region, ret);
34201 if (cfg.background) {
34202 // render grid on panel activation (if panel background)
34203 ret.on('activate', function(gp) {
34204 if (!gp.grid.rendered) {
34205 // gp.grid.render(el);
34209 // cfg.grid.render(el);
34215 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34216 // it was the old xcomponent building that caused this before.
34217 // espeically if border is the top element in the tree.
34227 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34229 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34230 this.add(region, ret);
34234 throw "Can not add '" + cfg.xtype + "' to Border";
34240 this.beginUpdate();
34244 Roo.each(xitems, function(i) {
34245 region = nb && i.region ? i.region : false;
34247 var add = ret.addxtype(i);
34250 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34251 if (!i.background) {
34252 abn[region] = nb[region] ;
34259 // make the last non-background panel active..
34260 //if (nb) { Roo.log(abn); }
34263 for(var r in abn) {
34264 region = this.getRegion(r);
34266 // tried using nb[r], but it does not work..
34268 region.showPanel(abn[r]);
34279 factory : function(cfg)
34282 var validRegions = Roo.bootstrap.layout.Border.regions;
34284 var target = cfg.region;
34287 var r = Roo.bootstrap.layout;
34291 return new r.North(cfg);
34293 return new r.South(cfg);
34295 return new r.East(cfg);
34297 return new r.West(cfg);
34299 return new r.Center(cfg);
34301 throw 'Layout region "'+target+'" not supported.';
34308 * Ext JS Library 1.1.1
34309 * Copyright(c) 2006-2007, Ext JS, LLC.
34311 * Originally Released Under LGPL - original licence link has changed is not relivant.
34314 * <script type="text/javascript">
34318 * @class Roo.bootstrap.layout.Basic
34319 * @extends Roo.util.Observable
34320 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34321 * and does not have a titlebar, tabs or any other features. All it does is size and position
34322 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34323 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34324 * @cfg {string} region the region that it inhabits..
34325 * @cfg {bool} skipConfig skip config?
34329 Roo.bootstrap.layout.Basic = function(config){
34331 this.mgr = config.mgr;
34333 this.position = config.region;
34335 var skipConfig = config.skipConfig;
34339 * @scope Roo.BasicLayoutRegion
34343 * @event beforeremove
34344 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34345 * @param {Roo.LayoutRegion} this
34346 * @param {Roo.ContentPanel} panel The panel
34347 * @param {Object} e The cancel event object
34349 "beforeremove" : true,
34351 * @event invalidated
34352 * Fires when the layout for this region is changed.
34353 * @param {Roo.LayoutRegion} this
34355 "invalidated" : true,
34357 * @event visibilitychange
34358 * Fires when this region is shown or hidden
34359 * @param {Roo.LayoutRegion} this
34360 * @param {Boolean} visibility true or false
34362 "visibilitychange" : true,
34364 * @event paneladded
34365 * Fires when a panel is added.
34366 * @param {Roo.LayoutRegion} this
34367 * @param {Roo.ContentPanel} panel The panel
34369 "paneladded" : true,
34371 * @event panelremoved
34372 * Fires when a panel is removed.
34373 * @param {Roo.LayoutRegion} this
34374 * @param {Roo.ContentPanel} panel The panel
34376 "panelremoved" : true,
34378 * @event beforecollapse
34379 * Fires when this region before collapse.
34380 * @param {Roo.LayoutRegion} this
34382 "beforecollapse" : true,
34385 * Fires when this region is collapsed.
34386 * @param {Roo.LayoutRegion} this
34388 "collapsed" : true,
34391 * Fires when this region is expanded.
34392 * @param {Roo.LayoutRegion} this
34397 * Fires when this region is slid into view.
34398 * @param {Roo.LayoutRegion} this
34400 "slideshow" : true,
34403 * Fires when this region slides out of view.
34404 * @param {Roo.LayoutRegion} this
34406 "slidehide" : true,
34408 * @event panelactivated
34409 * Fires when a panel is activated.
34410 * @param {Roo.LayoutRegion} this
34411 * @param {Roo.ContentPanel} panel The activated panel
34413 "panelactivated" : true,
34416 * Fires when the user resizes this region.
34417 * @param {Roo.LayoutRegion} this
34418 * @param {Number} newSize The new size (width for east/west, height for north/south)
34422 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34423 this.panels = new Roo.util.MixedCollection();
34424 this.panels.getKey = this.getPanelId.createDelegate(this);
34426 this.activePanel = null;
34427 // ensure listeners are added...
34429 if (config.listeners || config.events) {
34430 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34431 listeners : config.listeners || {},
34432 events : config.events || {}
34436 if(skipConfig !== true){
34437 this.applyConfig(config);
34441 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34443 getPanelId : function(p){
34447 applyConfig : function(config){
34448 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34449 this.config = config;
34454 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34455 * the width, for horizontal (north, south) the height.
34456 * @param {Number} newSize The new width or height
34458 resizeTo : function(newSize){
34459 var el = this.el ? this.el :
34460 (this.activePanel ? this.activePanel.getEl() : null);
34462 switch(this.position){
34465 el.setWidth(newSize);
34466 this.fireEvent("resized", this, newSize);
34470 el.setHeight(newSize);
34471 this.fireEvent("resized", this, newSize);
34477 getBox : function(){
34478 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34481 getMargins : function(){
34482 return this.margins;
34485 updateBox : function(box){
34487 var el = this.activePanel.getEl();
34488 el.dom.style.left = box.x + "px";
34489 el.dom.style.top = box.y + "px";
34490 this.activePanel.setSize(box.width, box.height);
34494 * Returns the container element for this region.
34495 * @return {Roo.Element}
34497 getEl : function(){
34498 return this.activePanel;
34502 * Returns true if this region is currently visible.
34503 * @return {Boolean}
34505 isVisible : function(){
34506 return this.activePanel ? true : false;
34509 setActivePanel : function(panel){
34510 panel = this.getPanel(panel);
34511 if(this.activePanel && this.activePanel != panel){
34512 this.activePanel.setActiveState(false);
34513 this.activePanel.getEl().setLeftTop(-10000,-10000);
34515 this.activePanel = panel;
34516 panel.setActiveState(true);
34518 panel.setSize(this.box.width, this.box.height);
34520 this.fireEvent("panelactivated", this, panel);
34521 this.fireEvent("invalidated");
34525 * Show the specified panel.
34526 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34527 * @return {Roo.ContentPanel} The shown panel or null
34529 showPanel : function(panel){
34530 panel = this.getPanel(panel);
34532 this.setActivePanel(panel);
34538 * Get the active panel for this region.
34539 * @return {Roo.ContentPanel} The active panel or null
34541 getActivePanel : function(){
34542 return this.activePanel;
34546 * Add the passed ContentPanel(s)
34547 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34548 * @return {Roo.ContentPanel} The panel added (if only one was added)
34550 add : function(panel){
34551 if(arguments.length > 1){
34552 for(var i = 0, len = arguments.length; i < len; i++) {
34553 this.add(arguments[i]);
34557 if(this.hasPanel(panel)){
34558 this.showPanel(panel);
34561 var el = panel.getEl();
34562 if(el.dom.parentNode != this.mgr.el.dom){
34563 this.mgr.el.dom.appendChild(el.dom);
34565 if(panel.setRegion){
34566 panel.setRegion(this);
34568 this.panels.add(panel);
34569 el.setStyle("position", "absolute");
34570 if(!panel.background){
34571 this.setActivePanel(panel);
34572 if(this.config.initialSize && this.panels.getCount()==1){
34573 this.resizeTo(this.config.initialSize);
34576 this.fireEvent("paneladded", this, panel);
34581 * Returns true if the panel is in this region.
34582 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34583 * @return {Boolean}
34585 hasPanel : function(panel){
34586 if(typeof panel == "object"){ // must be panel obj
34587 panel = panel.getId();
34589 return this.getPanel(panel) ? true : false;
34593 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34594 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34595 * @param {Boolean} preservePanel Overrides the config preservePanel option
34596 * @return {Roo.ContentPanel} The panel that was removed
34598 remove : function(panel, preservePanel){
34599 panel = this.getPanel(panel);
34604 this.fireEvent("beforeremove", this, panel, e);
34605 if(e.cancel === true){
34608 var panelId = panel.getId();
34609 this.panels.removeKey(panelId);
34614 * Returns the panel specified or null if it's not in this region.
34615 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34616 * @return {Roo.ContentPanel}
34618 getPanel : function(id){
34619 if(typeof id == "object"){ // must be panel obj
34622 return this.panels.get(id);
34626 * Returns this regions position (north/south/east/west/center).
34629 getPosition: function(){
34630 return this.position;
34634 * Ext JS Library 1.1.1
34635 * Copyright(c) 2006-2007, Ext JS, LLC.
34637 * Originally Released Under LGPL - original licence link has changed is not relivant.
34640 * <script type="text/javascript">
34644 * @class Roo.bootstrap.layout.Region
34645 * @extends Roo.bootstrap.layout.Basic
34646 * This class represents a region in a layout manager.
34648 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34649 * @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})
34650 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34651 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34652 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34653 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34654 * @cfg {String} title The title for the region (overrides panel titles)
34655 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34656 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34657 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34658 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34659 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34660 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34661 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34662 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34663 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34664 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34666 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34667 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34668 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34669 * @cfg {Number} width For East/West panels
34670 * @cfg {Number} height For North/South panels
34671 * @cfg {Boolean} split To show the splitter
34672 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34674 * @cfg {string} cls Extra CSS classes to add to region
34676 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34677 * @cfg {string} region the region that it inhabits..
34680 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34681 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34683 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34684 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34685 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34687 Roo.bootstrap.layout.Region = function(config)
34689 this.applyConfig(config);
34691 var mgr = config.mgr;
34692 var pos = config.region;
34693 config.skipConfig = true;
34694 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34697 this.onRender(mgr.el);
34700 this.visible = true;
34701 this.collapsed = false;
34702 this.unrendered_panels = [];
34705 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34707 position: '', // set by wrapper (eg. north/south etc..)
34708 unrendered_panels : null, // unrendered panels.
34709 createBody : function(){
34710 /** This region's body element
34711 * @type Roo.Element */
34712 this.bodyEl = this.el.createChild({
34714 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34718 onRender: function(ctr, pos)
34720 var dh = Roo.DomHelper;
34721 /** This region's container element
34722 * @type Roo.Element */
34723 this.el = dh.append(ctr.dom, {
34725 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34727 /** This region's title element
34728 * @type Roo.Element */
34730 this.titleEl = dh.append(this.el.dom,
34733 unselectable: "on",
34734 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34736 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34737 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34740 this.titleEl.enableDisplayMode();
34741 /** This region's title text element
34742 * @type HTMLElement */
34743 this.titleTextEl = this.titleEl.dom.firstChild;
34744 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34746 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34747 this.closeBtn.enableDisplayMode();
34748 this.closeBtn.on("click", this.closeClicked, this);
34749 this.closeBtn.hide();
34751 this.createBody(this.config);
34752 if(this.config.hideWhenEmpty){
34754 this.on("paneladded", this.validateVisibility, this);
34755 this.on("panelremoved", this.validateVisibility, this);
34757 if(this.autoScroll){
34758 this.bodyEl.setStyle("overflow", "auto");
34760 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34762 //if(c.titlebar !== false){
34763 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34764 this.titleEl.hide();
34766 this.titleEl.show();
34767 if(this.config.title){
34768 this.titleTextEl.innerHTML = this.config.title;
34772 if(this.config.collapsed){
34773 this.collapse(true);
34775 if(this.config.hidden){
34779 if (this.unrendered_panels && this.unrendered_panels.length) {
34780 for (var i =0;i< this.unrendered_panels.length; i++) {
34781 this.add(this.unrendered_panels[i]);
34783 this.unrendered_panels = null;
34789 applyConfig : function(c)
34792 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34793 var dh = Roo.DomHelper;
34794 if(c.titlebar !== false){
34795 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34796 this.collapseBtn.on("click", this.collapse, this);
34797 this.collapseBtn.enableDisplayMode();
34799 if(c.showPin === true || this.showPin){
34800 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34801 this.stickBtn.enableDisplayMode();
34802 this.stickBtn.on("click", this.expand, this);
34803 this.stickBtn.hide();
34808 /** This region's collapsed element
34809 * @type Roo.Element */
34812 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34813 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34816 if(c.floatable !== false){
34817 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34818 this.collapsedEl.on("click", this.collapseClick, this);
34821 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34822 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34823 id: "message", unselectable: "on", style:{"float":"left"}});
34824 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34826 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34827 this.expandBtn.on("click", this.expand, this);
34831 if(this.collapseBtn){
34832 this.collapseBtn.setVisible(c.collapsible == true);
34835 this.cmargins = c.cmargins || this.cmargins ||
34836 (this.position == "west" || this.position == "east" ?
34837 {top: 0, left: 2, right:2, bottom: 0} :
34838 {top: 2, left: 0, right:0, bottom: 2});
34840 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34843 this.bottomTabs = c.tabPosition != "top";
34845 this.autoScroll = c.autoScroll || false;
34850 this.duration = c.duration || .30;
34851 this.slideDuration = c.slideDuration || .45;
34856 * Returns true if this region is currently visible.
34857 * @return {Boolean}
34859 isVisible : function(){
34860 return this.visible;
34864 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34865 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34867 //setCollapsedTitle : function(title){
34868 // title = title || " ";
34869 // if(this.collapsedTitleTextEl){
34870 // this.collapsedTitleTextEl.innerHTML = title;
34874 getBox : function(){
34876 // if(!this.collapsed){
34877 b = this.el.getBox(false, true);
34879 // b = this.collapsedEl.getBox(false, true);
34884 getMargins : function(){
34885 return this.margins;
34886 //return this.collapsed ? this.cmargins : this.margins;
34889 highlight : function(){
34890 this.el.addClass("x-layout-panel-dragover");
34893 unhighlight : function(){
34894 this.el.removeClass("x-layout-panel-dragover");
34897 updateBox : function(box)
34899 if (!this.bodyEl) {
34900 return; // not rendered yet..
34904 if(!this.collapsed){
34905 this.el.dom.style.left = box.x + "px";
34906 this.el.dom.style.top = box.y + "px";
34907 this.updateBody(box.width, box.height);
34909 this.collapsedEl.dom.style.left = box.x + "px";
34910 this.collapsedEl.dom.style.top = box.y + "px";
34911 this.collapsedEl.setSize(box.width, box.height);
34914 this.tabs.autoSizeTabs();
34918 updateBody : function(w, h)
34921 this.el.setWidth(w);
34922 w -= this.el.getBorderWidth("rl");
34923 if(this.config.adjustments){
34924 w += this.config.adjustments[0];
34927 if(h !== null && h > 0){
34928 this.el.setHeight(h);
34929 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34930 h -= this.el.getBorderWidth("tb");
34931 if(this.config.adjustments){
34932 h += this.config.adjustments[1];
34934 this.bodyEl.setHeight(h);
34936 h = this.tabs.syncHeight(h);
34939 if(this.panelSize){
34940 w = w !== null ? w : this.panelSize.width;
34941 h = h !== null ? h : this.panelSize.height;
34943 if(this.activePanel){
34944 var el = this.activePanel.getEl();
34945 w = w !== null ? w : el.getWidth();
34946 h = h !== null ? h : el.getHeight();
34947 this.panelSize = {width: w, height: h};
34948 this.activePanel.setSize(w, h);
34950 if(Roo.isIE && this.tabs){
34951 this.tabs.el.repaint();
34956 * Returns the container element for this region.
34957 * @return {Roo.Element}
34959 getEl : function(){
34964 * Hides this region.
34967 //if(!this.collapsed){
34968 this.el.dom.style.left = "-2000px";
34971 // this.collapsedEl.dom.style.left = "-2000px";
34972 // this.collapsedEl.hide();
34974 this.visible = false;
34975 this.fireEvent("visibilitychange", this, false);
34979 * Shows this region if it was previously hidden.
34982 //if(!this.collapsed){
34985 // this.collapsedEl.show();
34987 this.visible = true;
34988 this.fireEvent("visibilitychange", this, true);
34991 closeClicked : function(){
34992 if(this.activePanel){
34993 this.remove(this.activePanel);
34997 collapseClick : function(e){
34999 e.stopPropagation();
35002 e.stopPropagation();
35008 * Collapses this region.
35009 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35012 collapse : function(skipAnim, skipCheck = false){
35013 if(this.collapsed) {
35017 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35019 this.collapsed = true;
35021 this.split.el.hide();
35023 if(this.config.animate && skipAnim !== true){
35024 this.fireEvent("invalidated", this);
35025 this.animateCollapse();
35027 this.el.setLocation(-20000,-20000);
35029 this.collapsedEl.show();
35030 this.fireEvent("collapsed", this);
35031 this.fireEvent("invalidated", this);
35037 animateCollapse : function(){
35042 * Expands this region if it was previously collapsed.
35043 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35044 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35047 expand : function(e, skipAnim){
35049 e.stopPropagation();
35051 if(!this.collapsed || this.el.hasActiveFx()) {
35055 this.afterSlideIn();
35058 this.collapsed = false;
35059 if(this.config.animate && skipAnim !== true){
35060 this.animateExpand();
35064 this.split.el.show();
35066 this.collapsedEl.setLocation(-2000,-2000);
35067 this.collapsedEl.hide();
35068 this.fireEvent("invalidated", this);
35069 this.fireEvent("expanded", this);
35073 animateExpand : function(){
35077 initTabs : function()
35079 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35081 var ts = new Roo.bootstrap.panel.Tabs({
35082 el: this.bodyEl.dom,
35083 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35084 disableTooltips: this.config.disableTabTips,
35085 toolbar : this.config.toolbar
35088 if(this.config.hideTabs){
35089 ts.stripWrap.setDisplayed(false);
35092 ts.resizeTabs = this.config.resizeTabs === true;
35093 ts.minTabWidth = this.config.minTabWidth || 40;
35094 ts.maxTabWidth = this.config.maxTabWidth || 250;
35095 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35096 ts.monitorResize = false;
35097 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35098 ts.bodyEl.addClass('roo-layout-tabs-body');
35099 this.panels.each(this.initPanelAsTab, this);
35102 initPanelAsTab : function(panel){
35103 var ti = this.tabs.addTab(
35107 this.config.closeOnTab && panel.isClosable(),
35110 if(panel.tabTip !== undefined){
35111 ti.setTooltip(panel.tabTip);
35113 ti.on("activate", function(){
35114 this.setActivePanel(panel);
35117 if(this.config.closeOnTab){
35118 ti.on("beforeclose", function(t, e){
35120 this.remove(panel);
35124 panel.tabItem = ti;
35129 updatePanelTitle : function(panel, title)
35131 if(this.activePanel == panel){
35132 this.updateTitle(title);
35135 var ti = this.tabs.getTab(panel.getEl().id);
35137 if(panel.tabTip !== undefined){
35138 ti.setTooltip(panel.tabTip);
35143 updateTitle : function(title){
35144 if(this.titleTextEl && !this.config.title){
35145 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35149 setActivePanel : function(panel)
35151 panel = this.getPanel(panel);
35152 if(this.activePanel && this.activePanel != panel){
35153 this.activePanel.setActiveState(false);
35155 this.activePanel = panel;
35156 panel.setActiveState(true);
35157 if(this.panelSize){
35158 panel.setSize(this.panelSize.width, this.panelSize.height);
35161 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35163 this.updateTitle(panel.getTitle());
35165 this.fireEvent("invalidated", this);
35167 this.fireEvent("panelactivated", this, panel);
35171 * Shows the specified panel.
35172 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35173 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35175 showPanel : function(panel)
35177 panel = this.getPanel(panel);
35180 var tab = this.tabs.getTab(panel.getEl().id);
35181 if(tab.isHidden()){
35182 this.tabs.unhideTab(tab.id);
35186 this.setActivePanel(panel);
35193 * Get the active panel for this region.
35194 * @return {Roo.ContentPanel} The active panel or null
35196 getActivePanel : function(){
35197 return this.activePanel;
35200 validateVisibility : function(){
35201 if(this.panels.getCount() < 1){
35202 this.updateTitle(" ");
35203 this.closeBtn.hide();
35206 if(!this.isVisible()){
35213 * Adds the passed ContentPanel(s) to this region.
35214 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35215 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35217 add : function(panel)
35219 if(arguments.length > 1){
35220 for(var i = 0, len = arguments.length; i < len; i++) {
35221 this.add(arguments[i]);
35226 // if we have not been rendered yet, then we can not really do much of this..
35227 if (!this.bodyEl) {
35228 this.unrendered_panels.push(panel);
35235 if(this.hasPanel(panel)){
35236 this.showPanel(panel);
35239 panel.setRegion(this);
35240 this.panels.add(panel);
35241 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35242 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35243 // and hide them... ???
35244 this.bodyEl.dom.appendChild(panel.getEl().dom);
35245 if(panel.background !== true){
35246 this.setActivePanel(panel);
35248 this.fireEvent("paneladded", this, panel);
35255 this.initPanelAsTab(panel);
35259 if(panel.background !== true){
35260 this.tabs.activate(panel.getEl().id);
35262 this.fireEvent("paneladded", this, panel);
35267 * Hides the tab for the specified panel.
35268 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35270 hidePanel : function(panel){
35271 if(this.tabs && (panel = this.getPanel(panel))){
35272 this.tabs.hideTab(panel.getEl().id);
35277 * Unhides the tab for a previously hidden panel.
35278 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35280 unhidePanel : function(panel){
35281 if(this.tabs && (panel = this.getPanel(panel))){
35282 this.tabs.unhideTab(panel.getEl().id);
35286 clearPanels : function(){
35287 while(this.panels.getCount() > 0){
35288 this.remove(this.panels.first());
35293 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35294 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35295 * @param {Boolean} preservePanel Overrides the config preservePanel option
35296 * @return {Roo.ContentPanel} The panel that was removed
35298 remove : function(panel, preservePanel)
35300 panel = this.getPanel(panel);
35305 this.fireEvent("beforeremove", this, panel, e);
35306 if(e.cancel === true){
35309 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35310 var panelId = panel.getId();
35311 this.panels.removeKey(panelId);
35313 document.body.appendChild(panel.getEl().dom);
35316 this.tabs.removeTab(panel.getEl().id);
35317 }else if (!preservePanel){
35318 this.bodyEl.dom.removeChild(panel.getEl().dom);
35320 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35321 var p = this.panels.first();
35322 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35323 tempEl.appendChild(p.getEl().dom);
35324 this.bodyEl.update("");
35325 this.bodyEl.dom.appendChild(p.getEl().dom);
35327 this.updateTitle(p.getTitle());
35329 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35330 this.setActivePanel(p);
35332 panel.setRegion(null);
35333 if(this.activePanel == panel){
35334 this.activePanel = null;
35336 if(this.config.autoDestroy !== false && preservePanel !== true){
35337 try{panel.destroy();}catch(e){}
35339 this.fireEvent("panelremoved", this, panel);
35344 * Returns the TabPanel component used by this region
35345 * @return {Roo.TabPanel}
35347 getTabs : function(){
35351 createTool : function(parentEl, className){
35352 var btn = Roo.DomHelper.append(parentEl, {
35354 cls: "x-layout-tools-button",
35357 cls: "roo-layout-tools-button-inner " + className,
35361 btn.addClassOnOver("roo-layout-tools-button-over");
35366 * Ext JS Library 1.1.1
35367 * Copyright(c) 2006-2007, Ext JS, LLC.
35369 * Originally Released Under LGPL - original licence link has changed is not relivant.
35372 * <script type="text/javascript">
35378 * @class Roo.SplitLayoutRegion
35379 * @extends Roo.LayoutRegion
35380 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35382 Roo.bootstrap.layout.Split = function(config){
35383 this.cursor = config.cursor;
35384 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35387 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35389 splitTip : "Drag to resize.",
35390 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35391 useSplitTips : false,
35393 applyConfig : function(config){
35394 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35397 onRender : function(ctr,pos) {
35399 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35400 if(!this.config.split){
35405 var splitEl = Roo.DomHelper.append(ctr.dom, {
35407 id: this.el.id + "-split",
35408 cls: "roo-layout-split roo-layout-split-"+this.position,
35411 /** The SplitBar for this region
35412 * @type Roo.SplitBar */
35413 // does not exist yet...
35414 Roo.log([this.position, this.orientation]);
35416 this.split = new Roo.bootstrap.SplitBar({
35417 dragElement : splitEl,
35418 resizingElement: this.el,
35419 orientation : this.orientation
35422 this.split.on("moved", this.onSplitMove, this);
35423 this.split.useShim = this.config.useShim === true;
35424 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35425 if(this.useSplitTips){
35426 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35428 //if(config.collapsible){
35429 // this.split.el.on("dblclick", this.collapse, this);
35432 if(typeof this.config.minSize != "undefined"){
35433 this.split.minSize = this.config.minSize;
35435 if(typeof this.config.maxSize != "undefined"){
35436 this.split.maxSize = this.config.maxSize;
35438 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35439 this.hideSplitter();
35444 getHMaxSize : function(){
35445 var cmax = this.config.maxSize || 10000;
35446 var center = this.mgr.getRegion("center");
35447 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35450 getVMaxSize : function(){
35451 var cmax = this.config.maxSize || 10000;
35452 var center = this.mgr.getRegion("center");
35453 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35456 onSplitMove : function(split, newSize){
35457 this.fireEvent("resized", this, newSize);
35461 * Returns the {@link Roo.SplitBar} for this region.
35462 * @return {Roo.SplitBar}
35464 getSplitBar : function(){
35469 this.hideSplitter();
35470 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35473 hideSplitter : function(){
35475 this.split.el.setLocation(-2000,-2000);
35476 this.split.el.hide();
35482 this.split.el.show();
35484 Roo.bootstrap.layout.Split.superclass.show.call(this);
35487 beforeSlide: function(){
35488 if(Roo.isGecko){// firefox overflow auto bug workaround
35489 this.bodyEl.clip();
35491 this.tabs.bodyEl.clip();
35493 if(this.activePanel){
35494 this.activePanel.getEl().clip();
35496 if(this.activePanel.beforeSlide){
35497 this.activePanel.beforeSlide();
35503 afterSlide : function(){
35504 if(Roo.isGecko){// firefox overflow auto bug workaround
35505 this.bodyEl.unclip();
35507 this.tabs.bodyEl.unclip();
35509 if(this.activePanel){
35510 this.activePanel.getEl().unclip();
35511 if(this.activePanel.afterSlide){
35512 this.activePanel.afterSlide();
35518 initAutoHide : function(){
35519 if(this.autoHide !== false){
35520 if(!this.autoHideHd){
35521 var st = new Roo.util.DelayedTask(this.slideIn, this);
35522 this.autoHideHd = {
35523 "mouseout": function(e){
35524 if(!e.within(this.el, true)){
35528 "mouseover" : function(e){
35534 this.el.on(this.autoHideHd);
35538 clearAutoHide : function(){
35539 if(this.autoHide !== false){
35540 this.el.un("mouseout", this.autoHideHd.mouseout);
35541 this.el.un("mouseover", this.autoHideHd.mouseover);
35545 clearMonitor : function(){
35546 Roo.get(document).un("click", this.slideInIf, this);
35549 // these names are backwards but not changed for compat
35550 slideOut : function(){
35551 if(this.isSlid || this.el.hasActiveFx()){
35554 this.isSlid = true;
35555 if(this.collapseBtn){
35556 this.collapseBtn.hide();
35558 this.closeBtnState = this.closeBtn.getStyle('display');
35559 this.closeBtn.hide();
35561 this.stickBtn.show();
35564 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35565 this.beforeSlide();
35566 this.el.setStyle("z-index", 10001);
35567 this.el.slideIn(this.getSlideAnchor(), {
35568 callback: function(){
35570 this.initAutoHide();
35571 Roo.get(document).on("click", this.slideInIf, this);
35572 this.fireEvent("slideshow", this);
35579 afterSlideIn : function(){
35580 this.clearAutoHide();
35581 this.isSlid = false;
35582 this.clearMonitor();
35583 this.el.setStyle("z-index", "");
35584 if(this.collapseBtn){
35585 this.collapseBtn.show();
35587 this.closeBtn.setStyle('display', this.closeBtnState);
35589 this.stickBtn.hide();
35591 this.fireEvent("slidehide", this);
35594 slideIn : function(cb){
35595 if(!this.isSlid || this.el.hasActiveFx()){
35599 this.isSlid = false;
35600 this.beforeSlide();
35601 this.el.slideOut(this.getSlideAnchor(), {
35602 callback: function(){
35603 this.el.setLeftTop(-10000, -10000);
35605 this.afterSlideIn();
35613 slideInIf : function(e){
35614 if(!e.within(this.el)){
35619 animateCollapse : function(){
35620 this.beforeSlide();
35621 this.el.setStyle("z-index", 20000);
35622 var anchor = this.getSlideAnchor();
35623 this.el.slideOut(anchor, {
35624 callback : function(){
35625 this.el.setStyle("z-index", "");
35626 this.collapsedEl.slideIn(anchor, {duration:.3});
35628 this.el.setLocation(-10000,-10000);
35630 this.fireEvent("collapsed", this);
35637 animateExpand : function(){
35638 this.beforeSlide();
35639 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35640 this.el.setStyle("z-index", 20000);
35641 this.collapsedEl.hide({
35644 this.el.slideIn(this.getSlideAnchor(), {
35645 callback : function(){
35646 this.el.setStyle("z-index", "");
35649 this.split.el.show();
35651 this.fireEvent("invalidated", this);
35652 this.fireEvent("expanded", this);
35680 getAnchor : function(){
35681 return this.anchors[this.position];
35684 getCollapseAnchor : function(){
35685 return this.canchors[this.position];
35688 getSlideAnchor : function(){
35689 return this.sanchors[this.position];
35692 getAlignAdj : function(){
35693 var cm = this.cmargins;
35694 switch(this.position){
35710 getExpandAdj : function(){
35711 var c = this.collapsedEl, cm = this.cmargins;
35712 switch(this.position){
35714 return [-(cm.right+c.getWidth()+cm.left), 0];
35717 return [cm.right+c.getWidth()+cm.left, 0];
35720 return [0, -(cm.top+cm.bottom+c.getHeight())];
35723 return [0, cm.top+cm.bottom+c.getHeight()];
35729 * Ext JS Library 1.1.1
35730 * Copyright(c) 2006-2007, Ext JS, LLC.
35732 * Originally Released Under LGPL - original licence link has changed is not relivant.
35735 * <script type="text/javascript">
35738 * These classes are private internal classes
35740 Roo.bootstrap.layout.Center = function(config){
35741 config.region = "center";
35742 Roo.bootstrap.layout.Region.call(this, config);
35743 this.visible = true;
35744 this.minWidth = config.minWidth || 20;
35745 this.minHeight = config.minHeight || 20;
35748 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35750 // center panel can't be hidden
35754 // center panel can't be hidden
35757 getMinWidth: function(){
35758 return this.minWidth;
35761 getMinHeight: function(){
35762 return this.minHeight;
35775 Roo.bootstrap.layout.North = function(config)
35777 config.region = 'north';
35778 config.cursor = 'n-resize';
35780 Roo.bootstrap.layout.Split.call(this, config);
35784 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35785 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35786 this.split.el.addClass("roo-layout-split-v");
35788 var size = config.initialSize || config.height;
35789 if(typeof size != "undefined"){
35790 this.el.setHeight(size);
35793 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35795 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35799 getBox : function(){
35800 if(this.collapsed){
35801 return this.collapsedEl.getBox();
35803 var box = this.el.getBox();
35805 box.height += this.split.el.getHeight();
35810 updateBox : function(box){
35811 if(this.split && !this.collapsed){
35812 box.height -= this.split.el.getHeight();
35813 this.split.el.setLeft(box.x);
35814 this.split.el.setTop(box.y+box.height);
35815 this.split.el.setWidth(box.width);
35817 if(this.collapsed){
35818 this.updateBody(box.width, null);
35820 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35828 Roo.bootstrap.layout.South = function(config){
35829 config.region = 'south';
35830 config.cursor = 's-resize';
35831 Roo.bootstrap.layout.Split.call(this, config);
35833 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35834 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35835 this.split.el.addClass("roo-layout-split-v");
35837 var size = config.initialSize || config.height;
35838 if(typeof size != "undefined"){
35839 this.el.setHeight(size);
35843 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35844 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35845 getBox : function(){
35846 if(this.collapsed){
35847 return this.collapsedEl.getBox();
35849 var box = this.el.getBox();
35851 var sh = this.split.el.getHeight();
35858 updateBox : function(box){
35859 if(this.split && !this.collapsed){
35860 var sh = this.split.el.getHeight();
35863 this.split.el.setLeft(box.x);
35864 this.split.el.setTop(box.y-sh);
35865 this.split.el.setWidth(box.width);
35867 if(this.collapsed){
35868 this.updateBody(box.width, null);
35870 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35874 Roo.bootstrap.layout.East = function(config){
35875 config.region = "east";
35876 config.cursor = "e-resize";
35877 Roo.bootstrap.layout.Split.call(this, config);
35879 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35880 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35881 this.split.el.addClass("roo-layout-split-h");
35883 var size = config.initialSize || config.width;
35884 if(typeof size != "undefined"){
35885 this.el.setWidth(size);
35888 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35889 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35890 getBox : function(){
35891 if(this.collapsed){
35892 return this.collapsedEl.getBox();
35894 var box = this.el.getBox();
35896 var sw = this.split.el.getWidth();
35903 updateBox : function(box){
35904 if(this.split && !this.collapsed){
35905 var sw = this.split.el.getWidth();
35907 this.split.el.setLeft(box.x);
35908 this.split.el.setTop(box.y);
35909 this.split.el.setHeight(box.height);
35912 if(this.collapsed){
35913 this.updateBody(null, box.height);
35915 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35919 Roo.bootstrap.layout.West = function(config){
35920 config.region = "west";
35921 config.cursor = "w-resize";
35923 Roo.bootstrap.layout.Split.call(this, config);
35925 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35926 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35927 this.split.el.addClass("roo-layout-split-h");
35931 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35932 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35934 onRender: function(ctr, pos)
35936 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35937 var size = this.config.initialSize || this.config.width;
35938 if(typeof size != "undefined"){
35939 this.el.setWidth(size);
35943 getBox : function(){
35944 if(this.collapsed){
35945 return this.collapsedEl.getBox();
35947 var box = this.el.getBox();
35949 box.width += this.split.el.getWidth();
35954 updateBox : function(box){
35955 if(this.split && !this.collapsed){
35956 var sw = this.split.el.getWidth();
35958 this.split.el.setLeft(box.x+box.width);
35959 this.split.el.setTop(box.y);
35960 this.split.el.setHeight(box.height);
35962 if(this.collapsed){
35963 this.updateBody(null, box.height);
35965 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35968 Roo.namespace("Roo.bootstrap.panel");/*
35970 * Ext JS Library 1.1.1
35971 * Copyright(c) 2006-2007, Ext JS, LLC.
35973 * Originally Released Under LGPL - original licence link has changed is not relivant.
35976 * <script type="text/javascript">
35979 * @class Roo.ContentPanel
35980 * @extends Roo.util.Observable
35981 * A basic ContentPanel element.
35982 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35983 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35984 * @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
35985 * @cfg {Boolean} closable True if the panel can be closed/removed
35986 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35987 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35988 * @cfg {Toolbar} toolbar A toolbar for this panel
35989 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35990 * @cfg {String} title The title for this panel
35991 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35992 * @cfg {String} url Calls {@link #setUrl} with this value
35993 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35994 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35995 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35996 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35997 * @cfg {Boolean} badges render the badges
36000 * Create a new ContentPanel.
36001 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36002 * @param {String/Object} config A string to set only the title or a config object
36003 * @param {String} content (optional) Set the HTML content for this panel
36004 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36006 Roo.bootstrap.panel.Content = function( config){
36008 this.tpl = config.tpl || false;
36010 var el = config.el;
36011 var content = config.content;
36013 if(config.autoCreate){ // xtype is available if this is called from factory
36016 this.el = Roo.get(el);
36017 if(!this.el && config && config.autoCreate){
36018 if(typeof config.autoCreate == "object"){
36019 if(!config.autoCreate.id){
36020 config.autoCreate.id = config.id||el;
36022 this.el = Roo.DomHelper.append(document.body,
36023 config.autoCreate, true);
36025 var elcfg = { tag: "div",
36026 cls: "roo-layout-inactive-content",
36030 elcfg.html = config.html;
36034 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36037 this.closable = false;
36038 this.loaded = false;
36039 this.active = false;
36042 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36044 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36046 this.wrapEl = this.el; //this.el.wrap();
36048 if (config.toolbar.items) {
36049 ti = config.toolbar.items ;
36050 delete config.toolbar.items ;
36054 this.toolbar.render(this.wrapEl, 'before');
36055 for(var i =0;i < ti.length;i++) {
36056 // Roo.log(['add child', items[i]]);
36057 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36059 this.toolbar.items = nitems;
36060 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36061 delete config.toolbar;
36065 // xtype created footer. - not sure if will work as we normally have to render first..
36066 if (this.footer && !this.footer.el && this.footer.xtype) {
36067 if (!this.wrapEl) {
36068 this.wrapEl = this.el.wrap();
36071 this.footer.container = this.wrapEl.createChild();
36073 this.footer = Roo.factory(this.footer, Roo);
36078 if(typeof config == "string"){
36079 this.title = config;
36081 Roo.apply(this, config);
36085 this.resizeEl = Roo.get(this.resizeEl, true);
36087 this.resizeEl = this.el;
36089 // handle view.xtype
36097 * Fires when this panel is activated.
36098 * @param {Roo.ContentPanel} this
36102 * @event deactivate
36103 * Fires when this panel is activated.
36104 * @param {Roo.ContentPanel} this
36106 "deactivate" : true,
36110 * Fires when this panel is resized if fitToFrame is true.
36111 * @param {Roo.ContentPanel} this
36112 * @param {Number} width The width after any component adjustments
36113 * @param {Number} height The height after any component adjustments
36119 * Fires when this tab is created
36120 * @param {Roo.ContentPanel} this
36131 if(this.autoScroll){
36132 this.resizeEl.setStyle("overflow", "auto");
36134 // fix randome scrolling
36135 //this.el.on('scroll', function() {
36136 // Roo.log('fix random scolling');
36137 // this.scrollTo('top',0);
36140 content = content || this.content;
36142 this.setContent(content);
36144 if(config && config.url){
36145 this.setUrl(this.url, this.params, this.loadOnce);
36150 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36152 if (this.view && typeof(this.view.xtype) != 'undefined') {
36153 this.view.el = this.el.appendChild(document.createElement("div"));
36154 this.view = Roo.factory(this.view);
36155 this.view.render && this.view.render(false, '');
36159 this.fireEvent('render', this);
36162 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36166 setRegion : function(region){
36167 this.region = region;
36168 this.setActiveClass(region && !this.background);
36172 setActiveClass: function(state)
36175 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36176 this.el.setStyle('position','relative');
36178 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36179 this.el.setStyle('position', 'absolute');
36184 * Returns the toolbar for this Panel if one was configured.
36185 * @return {Roo.Toolbar}
36187 getToolbar : function(){
36188 return this.toolbar;
36191 setActiveState : function(active)
36193 this.active = active;
36194 this.setActiveClass(active);
36196 this.fireEvent("deactivate", this);
36198 this.fireEvent("activate", this);
36202 * Updates this panel's element
36203 * @param {String} content The new content
36204 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36206 setContent : function(content, loadScripts){
36207 this.el.update(content, loadScripts);
36210 ignoreResize : function(w, h){
36211 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36214 this.lastSize = {width: w, height: h};
36219 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36220 * @return {Roo.UpdateManager} The UpdateManager
36222 getUpdateManager : function(){
36223 return this.el.getUpdateManager();
36226 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36227 * @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:
36230 url: "your-url.php",
36231 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36232 callback: yourFunction,
36233 scope: yourObject, //(optional scope)
36236 text: "Loading...",
36241 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36242 * 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.
36243 * @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}
36244 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36245 * @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.
36246 * @return {Roo.ContentPanel} this
36249 var um = this.el.getUpdateManager();
36250 um.update.apply(um, arguments);
36256 * 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.
36257 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36258 * @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)
36259 * @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)
36260 * @return {Roo.UpdateManager} The UpdateManager
36262 setUrl : function(url, params, loadOnce){
36263 if(this.refreshDelegate){
36264 this.removeListener("activate", this.refreshDelegate);
36266 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36267 this.on("activate", this.refreshDelegate);
36268 return this.el.getUpdateManager();
36271 _handleRefresh : function(url, params, loadOnce){
36272 if(!loadOnce || !this.loaded){
36273 var updater = this.el.getUpdateManager();
36274 updater.update(url, params, this._setLoaded.createDelegate(this));
36278 _setLoaded : function(){
36279 this.loaded = true;
36283 * Returns this panel's id
36286 getId : function(){
36291 * Returns this panel's element - used by regiosn to add.
36292 * @return {Roo.Element}
36294 getEl : function(){
36295 return this.wrapEl || this.el;
36300 adjustForComponents : function(width, height)
36302 //Roo.log('adjustForComponents ');
36303 if(this.resizeEl != this.el){
36304 width -= this.el.getFrameWidth('lr');
36305 height -= this.el.getFrameWidth('tb');
36308 var te = this.toolbar.getEl();
36309 te.setWidth(width);
36310 height -= te.getHeight();
36313 var te = this.footer.getEl();
36314 te.setWidth(width);
36315 height -= te.getHeight();
36319 if(this.adjustments){
36320 width += this.adjustments[0];
36321 height += this.adjustments[1];
36323 return {"width": width, "height": height};
36326 setSize : function(width, height){
36327 if(this.fitToFrame && !this.ignoreResize(width, height)){
36328 if(this.fitContainer && this.resizeEl != this.el){
36329 this.el.setSize(width, height);
36331 var size = this.adjustForComponents(width, height);
36332 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36333 this.fireEvent('resize', this, size.width, size.height);
36338 * Returns this panel's title
36341 getTitle : function(){
36343 if (typeof(this.title) != 'object') {
36348 for (var k in this.title) {
36349 if (!this.title.hasOwnProperty(k)) {
36353 if (k.indexOf('-') >= 0) {
36354 var s = k.split('-');
36355 for (var i = 0; i<s.length; i++) {
36356 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36359 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36366 * Set this panel's title
36367 * @param {String} title
36369 setTitle : function(title){
36370 this.title = title;
36372 this.region.updatePanelTitle(this, title);
36377 * Returns true is this panel was configured to be closable
36378 * @return {Boolean}
36380 isClosable : function(){
36381 return this.closable;
36384 beforeSlide : function(){
36386 this.resizeEl.clip();
36389 afterSlide : function(){
36391 this.resizeEl.unclip();
36395 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36396 * Will fail silently if the {@link #setUrl} method has not been called.
36397 * This does not activate the panel, just updates its content.
36399 refresh : function(){
36400 if(this.refreshDelegate){
36401 this.loaded = false;
36402 this.refreshDelegate();
36407 * Destroys this panel
36409 destroy : function(){
36410 this.el.removeAllListeners();
36411 var tempEl = document.createElement("span");
36412 tempEl.appendChild(this.el.dom);
36413 tempEl.innerHTML = "";
36419 * form - if the content panel contains a form - this is a reference to it.
36420 * @type {Roo.form.Form}
36424 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36425 * This contains a reference to it.
36431 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36441 * @param {Object} cfg Xtype definition of item to add.
36445 getChildContainer: function () {
36446 return this.getEl();
36451 var ret = new Roo.factory(cfg);
36456 if (cfg.xtype.match(/^Form$/)) {
36459 //if (this.footer) {
36460 // el = this.footer.container.insertSibling(false, 'before');
36462 el = this.el.createChild();
36465 this.form = new Roo.form.Form(cfg);
36468 if ( this.form.allItems.length) {
36469 this.form.render(el.dom);
36473 // should only have one of theses..
36474 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36475 // views.. should not be just added - used named prop 'view''
36477 cfg.el = this.el.appendChild(document.createElement("div"));
36480 var ret = new Roo.factory(cfg);
36482 ret.render && ret.render(false, ''); // render blank..
36492 * @class Roo.bootstrap.panel.Grid
36493 * @extends Roo.bootstrap.panel.Content
36495 * Create a new GridPanel.
36496 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36497 * @param {Object} config A the config object
36503 Roo.bootstrap.panel.Grid = function(config)
36507 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36508 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36510 config.el = this.wrapper;
36511 //this.el = this.wrapper;
36513 if (config.container) {
36514 // ctor'ed from a Border/panel.grid
36517 this.wrapper.setStyle("overflow", "hidden");
36518 this.wrapper.addClass('roo-grid-container');
36523 if(config.toolbar){
36524 var tool_el = this.wrapper.createChild();
36525 this.toolbar = Roo.factory(config.toolbar);
36527 if (config.toolbar.items) {
36528 ti = config.toolbar.items ;
36529 delete config.toolbar.items ;
36533 this.toolbar.render(tool_el);
36534 for(var i =0;i < ti.length;i++) {
36535 // Roo.log(['add child', items[i]]);
36536 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36538 this.toolbar.items = nitems;
36540 delete config.toolbar;
36543 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36544 config.grid.scrollBody = true;;
36545 config.grid.monitorWindowResize = false; // turn off autosizing
36546 config.grid.autoHeight = false;
36547 config.grid.autoWidth = false;
36549 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36551 if (config.background) {
36552 // render grid on panel activation (if panel background)
36553 this.on('activate', function(gp) {
36554 if (!gp.grid.rendered) {
36555 gp.grid.render(this.wrapper);
36556 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36561 this.grid.render(this.wrapper);
36562 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36565 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36566 // ??? needed ??? config.el = this.wrapper;
36571 // xtype created footer. - not sure if will work as we normally have to render first..
36572 if (this.footer && !this.footer.el && this.footer.xtype) {
36574 var ctr = this.grid.getView().getFooterPanel(true);
36575 this.footer.dataSource = this.grid.dataSource;
36576 this.footer = Roo.factory(this.footer, Roo);
36577 this.footer.render(ctr);
36587 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36588 getId : function(){
36589 return this.grid.id;
36593 * Returns the grid for this panel
36594 * @return {Roo.bootstrap.Table}
36596 getGrid : function(){
36600 setSize : function(width, height){
36601 if(!this.ignoreResize(width, height)){
36602 var grid = this.grid;
36603 var size = this.adjustForComponents(width, height);
36604 var gridel = grid.getGridEl();
36605 gridel.setSize(size.width, size.height);
36607 var thd = grid.getGridEl().select('thead',true).first();
36608 var tbd = grid.getGridEl().select('tbody', true).first();
36610 tbd.setSize(width, height - thd.getHeight());
36619 beforeSlide : function(){
36620 this.grid.getView().scroller.clip();
36623 afterSlide : function(){
36624 this.grid.getView().scroller.unclip();
36627 destroy : function(){
36628 this.grid.destroy();
36630 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36635 * @class Roo.bootstrap.panel.Nest
36636 * @extends Roo.bootstrap.panel.Content
36638 * Create a new Panel, that can contain a layout.Border.
36641 * @param {Roo.BorderLayout} layout The layout for this panel
36642 * @param {String/Object} config A string to set only the title or a config object
36644 Roo.bootstrap.panel.Nest = function(config)
36646 // construct with only one argument..
36647 /* FIXME - implement nicer consturctors
36648 if (layout.layout) {
36650 layout = config.layout;
36651 delete config.layout;
36653 if (layout.xtype && !layout.getEl) {
36654 // then layout needs constructing..
36655 layout = Roo.factory(layout, Roo);
36659 config.el = config.layout.getEl();
36661 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36663 config.layout.monitorWindowResize = false; // turn off autosizing
36664 this.layout = config.layout;
36665 this.layout.getEl().addClass("roo-layout-nested-layout");
36672 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36674 setSize : function(width, height){
36675 if(!this.ignoreResize(width, height)){
36676 var size = this.adjustForComponents(width, height);
36677 var el = this.layout.getEl();
36678 if (size.height < 1) {
36679 el.setWidth(size.width);
36681 el.setSize(size.width, size.height);
36683 var touch = el.dom.offsetWidth;
36684 this.layout.layout();
36685 // ie requires a double layout on the first pass
36686 if(Roo.isIE && !this.initialized){
36687 this.initialized = true;
36688 this.layout.layout();
36693 // activate all subpanels if not currently active..
36695 setActiveState : function(active){
36696 this.active = active;
36697 this.setActiveClass(active);
36700 this.fireEvent("deactivate", this);
36704 this.fireEvent("activate", this);
36705 // not sure if this should happen before or after..
36706 if (!this.layout) {
36707 return; // should not happen..
36710 for (var r in this.layout.regions) {
36711 reg = this.layout.getRegion(r);
36712 if (reg.getActivePanel()) {
36713 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36714 reg.setActivePanel(reg.getActivePanel());
36717 if (!reg.panels.length) {
36720 reg.showPanel(reg.getPanel(0));
36729 * Returns the nested BorderLayout for this panel
36730 * @return {Roo.BorderLayout}
36732 getLayout : function(){
36733 return this.layout;
36737 * Adds a xtype elements to the layout of the nested panel
36741 xtype : 'ContentPanel',
36748 xtype : 'NestedLayoutPanel',
36754 items : [ ... list of content panels or nested layout panels.. ]
36758 * @param {Object} cfg Xtype definition of item to add.
36760 addxtype : function(cfg) {
36761 return this.layout.addxtype(cfg);
36766 * Ext JS Library 1.1.1
36767 * Copyright(c) 2006-2007, Ext JS, LLC.
36769 * Originally Released Under LGPL - original licence link has changed is not relivant.
36772 * <script type="text/javascript">
36775 * @class Roo.TabPanel
36776 * @extends Roo.util.Observable
36777 * A lightweight tab container.
36781 // basic tabs 1, built from existing content
36782 var tabs = new Roo.TabPanel("tabs1");
36783 tabs.addTab("script", "View Script");
36784 tabs.addTab("markup", "View Markup");
36785 tabs.activate("script");
36787 // more advanced tabs, built from javascript
36788 var jtabs = new Roo.TabPanel("jtabs");
36789 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36791 // set up the UpdateManager
36792 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36793 var updater = tab2.getUpdateManager();
36794 updater.setDefaultUrl("ajax1.htm");
36795 tab2.on('activate', updater.refresh, updater, true);
36797 // Use setUrl for Ajax loading
36798 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36799 tab3.setUrl("ajax2.htm", null, true);
36802 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36805 jtabs.activate("jtabs-1");
36808 * Create a new TabPanel.
36809 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36810 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36812 Roo.bootstrap.panel.Tabs = function(config){
36814 * The container element for this TabPanel.
36815 * @type Roo.Element
36817 this.el = Roo.get(config.el);
36820 if(typeof config == "boolean"){
36821 this.tabPosition = config ? "bottom" : "top";
36823 Roo.apply(this, config);
36827 if(this.tabPosition == "bottom"){
36828 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36829 this.el.addClass("roo-tabs-bottom");
36831 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36832 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36833 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36835 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36837 if(this.tabPosition != "bottom"){
36838 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36839 * @type Roo.Element
36841 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36842 this.el.addClass("roo-tabs-top");
36846 this.bodyEl.setStyle("position", "relative");
36848 this.active = null;
36849 this.activateDelegate = this.activate.createDelegate(this);
36854 * Fires when the active tab changes
36855 * @param {Roo.TabPanel} this
36856 * @param {Roo.TabPanelItem} activePanel The new active tab
36860 * @event beforetabchange
36861 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36862 * @param {Roo.TabPanel} this
36863 * @param {Object} e Set cancel to true on this object to cancel the tab change
36864 * @param {Roo.TabPanelItem} tab The tab being changed to
36866 "beforetabchange" : true
36869 Roo.EventManager.onWindowResize(this.onResize, this);
36870 this.cpad = this.el.getPadding("lr");
36871 this.hiddenCount = 0;
36874 // toolbar on the tabbar support...
36875 if (this.toolbar) {
36876 alert("no toolbar support yet");
36877 this.toolbar = false;
36879 var tcfg = this.toolbar;
36880 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36881 this.toolbar = new Roo.Toolbar(tcfg);
36882 if (Roo.isSafari) {
36883 var tbl = tcfg.container.child('table', true);
36884 tbl.setAttribute('width', '100%');
36892 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36895 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36897 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36899 tabPosition : "top",
36901 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36903 currentTabWidth : 0,
36905 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36909 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36913 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36915 preferredTabWidth : 175,
36917 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36919 resizeTabs : false,
36921 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36923 monitorResize : true,
36925 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36930 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36931 * @param {String} id The id of the div to use <b>or create</b>
36932 * @param {String} text The text for the tab
36933 * @param {String} content (optional) Content to put in the TabPanelItem body
36934 * @param {Boolean} closable (optional) True to create a close icon on the tab
36935 * @return {Roo.TabPanelItem} The created TabPanelItem
36937 addTab : function(id, text, content, closable, tpl)
36939 var item = new Roo.bootstrap.panel.TabItem({
36943 closable : closable,
36946 this.addTabItem(item);
36948 item.setContent(content);
36954 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36955 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36956 * @return {Roo.TabPanelItem}
36958 getTab : function(id){
36959 return this.items[id];
36963 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36964 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36966 hideTab : function(id){
36967 var t = this.items[id];
36970 this.hiddenCount++;
36971 this.autoSizeTabs();
36976 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36977 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36979 unhideTab : function(id){
36980 var t = this.items[id];
36982 t.setHidden(false);
36983 this.hiddenCount--;
36984 this.autoSizeTabs();
36989 * Adds an existing {@link Roo.TabPanelItem}.
36990 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36992 addTabItem : function(item){
36993 this.items[item.id] = item;
36994 this.items.push(item);
36995 // if(this.resizeTabs){
36996 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36997 // this.autoSizeTabs();
36999 // item.autoSize();
37004 * Removes a {@link Roo.TabPanelItem}.
37005 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37007 removeTab : function(id){
37008 var items = this.items;
37009 var tab = items[id];
37010 if(!tab) { return; }
37011 var index = items.indexOf(tab);
37012 if(this.active == tab && items.length > 1){
37013 var newTab = this.getNextAvailable(index);
37018 this.stripEl.dom.removeChild(tab.pnode.dom);
37019 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37020 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37022 items.splice(index, 1);
37023 delete this.items[tab.id];
37024 tab.fireEvent("close", tab);
37025 tab.purgeListeners();
37026 this.autoSizeTabs();
37029 getNextAvailable : function(start){
37030 var items = this.items;
37032 // look for a next tab that will slide over to
37033 // replace the one being removed
37034 while(index < items.length){
37035 var item = items[++index];
37036 if(item && !item.isHidden()){
37040 // if one isn't found select the previous tab (on the left)
37043 var item = items[--index];
37044 if(item && !item.isHidden()){
37052 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37053 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37055 disableTab : function(id){
37056 var tab = this.items[id];
37057 if(tab && this.active != tab){
37063 * Enables a {@link Roo.TabPanelItem} that is disabled.
37064 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37066 enableTab : function(id){
37067 var tab = this.items[id];
37072 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37073 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37074 * @return {Roo.TabPanelItem} The TabPanelItem.
37076 activate : function(id){
37077 var tab = this.items[id];
37081 if(tab == this.active || tab.disabled){
37085 this.fireEvent("beforetabchange", this, e, tab);
37086 if(e.cancel !== true && !tab.disabled){
37088 this.active.hide();
37090 this.active = this.items[id];
37091 this.active.show();
37092 this.fireEvent("tabchange", this, this.active);
37098 * Gets the active {@link Roo.TabPanelItem}.
37099 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37101 getActiveTab : function(){
37102 return this.active;
37106 * Updates the tab body element to fit the height of the container element
37107 * for overflow scrolling
37108 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37110 syncHeight : function(targetHeight){
37111 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37112 var bm = this.bodyEl.getMargins();
37113 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37114 this.bodyEl.setHeight(newHeight);
37118 onResize : function(){
37119 if(this.monitorResize){
37120 this.autoSizeTabs();
37125 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37127 beginUpdate : function(){
37128 this.updating = true;
37132 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37134 endUpdate : function(){
37135 this.updating = false;
37136 this.autoSizeTabs();
37140 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37142 autoSizeTabs : function(){
37143 var count = this.items.length;
37144 var vcount = count - this.hiddenCount;
37145 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37148 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37149 var availWidth = Math.floor(w / vcount);
37150 var b = this.stripBody;
37151 if(b.getWidth() > w){
37152 var tabs = this.items;
37153 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37154 if(availWidth < this.minTabWidth){
37155 /*if(!this.sleft){ // incomplete scrolling code
37156 this.createScrollButtons();
37159 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37162 if(this.currentTabWidth < this.preferredTabWidth){
37163 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37169 * Returns the number of tabs in this TabPanel.
37172 getCount : function(){
37173 return this.items.length;
37177 * Resizes all the tabs to the passed width
37178 * @param {Number} The new width
37180 setTabWidth : function(width){
37181 this.currentTabWidth = width;
37182 for(var i = 0, len = this.items.length; i < len; i++) {
37183 if(!this.items[i].isHidden()) {
37184 this.items[i].setWidth(width);
37190 * Destroys this TabPanel
37191 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37193 destroy : function(removeEl){
37194 Roo.EventManager.removeResizeListener(this.onResize, this);
37195 for(var i = 0, len = this.items.length; i < len; i++){
37196 this.items[i].purgeListeners();
37198 if(removeEl === true){
37199 this.el.update("");
37204 createStrip : function(container)
37206 var strip = document.createElement("nav");
37207 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37208 container.appendChild(strip);
37212 createStripList : function(strip)
37214 // div wrapper for retard IE
37215 // returns the "tr" element.
37216 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37217 //'<div class="x-tabs-strip-wrap">'+
37218 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37219 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37220 return strip.firstChild; //.firstChild.firstChild.firstChild;
37222 createBody : function(container)
37224 var body = document.createElement("div");
37225 Roo.id(body, "tab-body");
37226 //Roo.fly(body).addClass("x-tabs-body");
37227 Roo.fly(body).addClass("tab-content");
37228 container.appendChild(body);
37231 createItemBody :function(bodyEl, id){
37232 var body = Roo.getDom(id);
37234 body = document.createElement("div");
37237 //Roo.fly(body).addClass("x-tabs-item-body");
37238 Roo.fly(body).addClass("tab-pane");
37239 bodyEl.insertBefore(body, bodyEl.firstChild);
37243 createStripElements : function(stripEl, text, closable, tpl)
37245 var td = document.createElement("li"); // was td..
37248 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37251 stripEl.appendChild(td);
37253 td.className = "x-tabs-closable";
37254 if(!this.closeTpl){
37255 this.closeTpl = new Roo.Template(
37256 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37257 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37258 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37261 var el = this.closeTpl.overwrite(td, {"text": text});
37262 var close = el.getElementsByTagName("div")[0];
37263 var inner = el.getElementsByTagName("em")[0];
37264 return {"el": el, "close": close, "inner": inner};
37267 // not sure what this is..
37268 // if(!this.tabTpl){
37269 //this.tabTpl = new Roo.Template(
37270 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37271 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37273 // this.tabTpl = new Roo.Template(
37274 // '<a href="#">' +
37275 // '<span unselectable="on"' +
37276 // (this.disableTooltips ? '' : ' title="{text}"') +
37277 // ' >{text}</span></a>'
37283 var template = tpl || this.tabTpl || false;
37287 template = new Roo.Template(
37289 '<span unselectable="on"' +
37290 (this.disableTooltips ? '' : ' title="{text}"') +
37291 ' >{text}</span></a>'
37295 switch (typeof(template)) {
37299 template = new Roo.Template(template);
37305 var el = template.overwrite(td, {"text": text});
37307 var inner = el.getElementsByTagName("span")[0];
37309 return {"el": el, "inner": inner};
37317 * @class Roo.TabPanelItem
37318 * @extends Roo.util.Observable
37319 * Represents an individual item (tab plus body) in a TabPanel.
37320 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37321 * @param {String} id The id of this TabPanelItem
37322 * @param {String} text The text for the tab of this TabPanelItem
37323 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37325 Roo.bootstrap.panel.TabItem = function(config){
37327 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37328 * @type Roo.TabPanel
37330 this.tabPanel = config.panel;
37332 * The id for this TabPanelItem
37335 this.id = config.id;
37337 this.disabled = false;
37339 this.text = config.text;
37341 this.loaded = false;
37342 this.closable = config.closable;
37345 * The body element for this TabPanelItem.
37346 * @type Roo.Element
37348 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37349 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37350 this.bodyEl.setStyle("display", "block");
37351 this.bodyEl.setStyle("zoom", "1");
37352 //this.hideAction();
37354 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37356 this.el = Roo.get(els.el);
37357 this.inner = Roo.get(els.inner, true);
37358 this.textEl = Roo.get(this.el.dom.firstChild, true);
37359 this.pnode = Roo.get(els.el.parentNode, true);
37360 this.el.on("mousedown", this.onTabMouseDown, this);
37361 this.el.on("click", this.onTabClick, this);
37363 if(config.closable){
37364 var c = Roo.get(els.close, true);
37365 c.dom.title = this.closeText;
37366 c.addClassOnOver("close-over");
37367 c.on("click", this.closeClick, this);
37373 * Fires when this tab becomes the active tab.
37374 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37375 * @param {Roo.TabPanelItem} this
37379 * @event beforeclose
37380 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37381 * @param {Roo.TabPanelItem} this
37382 * @param {Object} e Set cancel to true on this object to cancel the close.
37384 "beforeclose": true,
37387 * Fires when this tab is closed.
37388 * @param {Roo.TabPanelItem} this
37392 * @event deactivate
37393 * Fires when this tab is no longer the active tab.
37394 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37395 * @param {Roo.TabPanelItem} this
37397 "deactivate" : true
37399 this.hidden = false;
37401 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37404 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37406 purgeListeners : function(){
37407 Roo.util.Observable.prototype.purgeListeners.call(this);
37408 this.el.removeAllListeners();
37411 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37414 this.pnode.addClass("active");
37417 this.tabPanel.stripWrap.repaint();
37419 this.fireEvent("activate", this.tabPanel, this);
37423 * Returns true if this tab is the active tab.
37424 * @return {Boolean}
37426 isActive : function(){
37427 return this.tabPanel.getActiveTab() == this;
37431 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37434 this.pnode.removeClass("active");
37436 this.fireEvent("deactivate", this.tabPanel, this);
37439 hideAction : function(){
37440 this.bodyEl.hide();
37441 this.bodyEl.setStyle("position", "absolute");
37442 this.bodyEl.setLeft("-20000px");
37443 this.bodyEl.setTop("-20000px");
37446 showAction : function(){
37447 this.bodyEl.setStyle("position", "relative");
37448 this.bodyEl.setTop("");
37449 this.bodyEl.setLeft("");
37450 this.bodyEl.show();
37454 * Set the tooltip for the tab.
37455 * @param {String} tooltip The tab's tooltip
37457 setTooltip : function(text){
37458 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37459 this.textEl.dom.qtip = text;
37460 this.textEl.dom.removeAttribute('title');
37462 this.textEl.dom.title = text;
37466 onTabClick : function(e){
37467 e.preventDefault();
37468 this.tabPanel.activate(this.id);
37471 onTabMouseDown : function(e){
37472 e.preventDefault();
37473 this.tabPanel.activate(this.id);
37476 getWidth : function(){
37477 return this.inner.getWidth();
37480 setWidth : function(width){
37481 var iwidth = width - this.pnode.getPadding("lr");
37482 this.inner.setWidth(iwidth);
37483 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37484 this.pnode.setWidth(width);
37488 * Show or hide the tab
37489 * @param {Boolean} hidden True to hide or false to show.
37491 setHidden : function(hidden){
37492 this.hidden = hidden;
37493 this.pnode.setStyle("display", hidden ? "none" : "");
37497 * Returns true if this tab is "hidden"
37498 * @return {Boolean}
37500 isHidden : function(){
37501 return this.hidden;
37505 * Returns the text for this tab
37508 getText : function(){
37512 autoSize : function(){
37513 //this.el.beginMeasure();
37514 this.textEl.setWidth(1);
37516 * #2804 [new] Tabs in Roojs
37517 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37519 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37520 //this.el.endMeasure();
37524 * Sets the text for the tab (Note: this also sets the tooltip text)
37525 * @param {String} text The tab's text and tooltip
37527 setText : function(text){
37529 this.textEl.update(text);
37530 this.setTooltip(text);
37531 //if(!this.tabPanel.resizeTabs){
37532 // this.autoSize();
37536 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37538 activate : function(){
37539 this.tabPanel.activate(this.id);
37543 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37545 disable : function(){
37546 if(this.tabPanel.active != this){
37547 this.disabled = true;
37548 this.pnode.addClass("disabled");
37553 * Enables this TabPanelItem if it was previously disabled.
37555 enable : function(){
37556 this.disabled = false;
37557 this.pnode.removeClass("disabled");
37561 * Sets the content for this TabPanelItem.
37562 * @param {String} content The content
37563 * @param {Boolean} loadScripts true to look for and load scripts
37565 setContent : function(content, loadScripts){
37566 this.bodyEl.update(content, loadScripts);
37570 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37571 * @return {Roo.UpdateManager} The UpdateManager
37573 getUpdateManager : function(){
37574 return this.bodyEl.getUpdateManager();
37578 * Set a URL to be used to load the content for this TabPanelItem.
37579 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37580 * @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)
37581 * @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)
37582 * @return {Roo.UpdateManager} The UpdateManager
37584 setUrl : function(url, params, loadOnce){
37585 if(this.refreshDelegate){
37586 this.un('activate', this.refreshDelegate);
37588 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37589 this.on("activate", this.refreshDelegate);
37590 return this.bodyEl.getUpdateManager();
37594 _handleRefresh : function(url, params, loadOnce){
37595 if(!loadOnce || !this.loaded){
37596 var updater = this.bodyEl.getUpdateManager();
37597 updater.update(url, params, this._setLoaded.createDelegate(this));
37602 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37603 * Will fail silently if the setUrl method has not been called.
37604 * This does not activate the panel, just updates its content.
37606 refresh : function(){
37607 if(this.refreshDelegate){
37608 this.loaded = false;
37609 this.refreshDelegate();
37614 _setLoaded : function(){
37615 this.loaded = true;
37619 closeClick : function(e){
37622 this.fireEvent("beforeclose", this, o);
37623 if(o.cancel !== true){
37624 this.tabPanel.removeTab(this.id);
37628 * The text displayed in the tooltip for the close icon.
37631 closeText : "Close this tab"